diff options
Diffstat (limited to 'release/scripts')
151 files changed, 25838 insertions, 10924 deletions
diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 6c3a46dc113de870a03191e4c0685238b0823ac +Subproject 371960484a38fc64e0a2635170a41a0d8ab2f6b diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject 15b25a42783d1e516b5298d70b582fae2559ae1 +Subproject 474702157831f1a58bb50f5240ab8b1b02b6ba3 diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py index b093920a4cb..c2b23f017fe 100644 --- a/release/scripts/freestyle/modules/parameter_editor.py +++ b/release/scripts/freestyle/modules/parameter_editor.py @@ -1206,7 +1206,7 @@ integration_types = { # main function for parameter processing def process(layer_name, lineset_name): scene = getCurrentScene() - layer = scene.render.layers[layer_name] + layer = scene.view_layers[layer_name] lineset = layer.freestyle_settings.linesets[lineset_name] linestyle = lineset.linestyle @@ -1538,16 +1538,9 @@ def process(layer_name, lineset_name): raise RuntimeError("No Thickness modifier with type", type(m), m) # -- Textures -- # has_tex = False - if scene.render.use_shading_nodes: - if linestyle.use_nodes and linestyle.node_tree: - shaders_list.append(BlenderTextureShader(linestyle.node_tree)) - has_tex = True - else: - if linestyle.use_texture: - textures = tuple(BlenderTextureShader(slot) for slot in linestyle.texture_slots if slot is not None) - if textures: - shaders_list.extend(textures) - has_tex = True + if linestyle.use_nodes and linestyle.node_tree: + shaders_list.append(BlenderTextureShader(linestyle.node_tree)) + has_tex = True if has_tex: shaders_list.append(StrokeTextureStepShader(linestyle.texture_spacing)) diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 5cb313ec41b..f73d23c150b 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -362,9 +362,38 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non _addon_remove(module_name) return None + # 1.1) fail when add-on is too old + # This is a temporary 2.8x migration check, so we can manage addons that are supported. + + # Silent default, we know these need updating. + if module_name in { + "io_anim_bvh", + "io_mesh_ply", + "io_mesh_stl", + "io_mesh_uv_layout", + "io_scene_3ds", + "io_scene_fbx", + "io_scene_obj", + "io_scene_x3d", + }: + return None + + try: + if mod.bl_info.get("blender", (0, 0, 0)) < (2, 80, 0): + raise Exception(f"Add-on '{module_name:s}' has not been upgraded to 2.8, ignoring") + except Exception as ex: + handle_error(ex) + return None + # 2) try register collected modules # removed, addons need to handle own registration now. + use_owner = mod.bl_info.get("use_owner", True) + if use_owner: + from _bpy import _bl_owner_id_get, _bl_owner_id_set + owner_id_prev = _bl_owner_id_get() + _bl_owner_id_set(module_name) + # 3) try run the modules register function try: mod.register() @@ -378,6 +407,9 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non if default_set: _addon_remove(module_name) return None + finally: + if use_owner: + _bl_owner_id_set(owner_id_prev) # * OK loaded successfully! * mod.__addon_enabled__ = True @@ -491,6 +523,7 @@ def module_bl_info(mod, info_basis=None): "category": "", "warning": "", "show_expanded": False, + "use_owner": True, } addon_info = getattr(mod, "bl_info", {}) @@ -508,5 +541,9 @@ def module_bl_info(mod, info_basis=None): if not addon_info["name"]: addon_info["name"] = mod.__name__ + # Temporary auto-magic, don't use_owner for import export menus. + if mod.bl_info["category"] == "Import-Export": + mod.bl_info["use_owner"] = False + addon_info["_init"] = None return addon_info diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 10a386039c4..b395aab7772 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -391,7 +391,7 @@ def dump_rna_messages(msgs, reports, settings, verbose=False): return def full_class_id(cls): - """Gives us 'ID.Lamp.AreaLamp' which is best for sorting.""" + """Gives us 'ID.Light.AreaLight' which is best for sorting.""" # Always the same issue, some classes listed in blacklist should actually no more exist (they have been # unregistered), but are still listed by __subclasses__() calls... :/ if cls in blacklist_rna_class: diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index 6adf7f1ef91..b811c1c7d71 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -442,7 +442,6 @@ class SpellChecker: "fedge", "fedges", "filmic", "fluidsim", - "frameserver", "freestyle", "enum", "enums", "gpencil", @@ -589,7 +588,6 @@ class SpellChecker: "yuv", "yuva", # Blender acronyms - "bge", "bli", "bpy", "bvh", diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py index 4159121cd90..16b0b107927 100644 --- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py +++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py @@ -31,7 +31,7 @@ from mathutils import ( ) -INTERN_PREVIEW_TYPES = {'MATERIAL', 'LAMP', 'WORLD', 'TEXTURE', 'IMAGE'} +INTERN_PREVIEW_TYPES = {'MATERIAL', 'LIGHT', 'WORLD', 'TEXTURE', 'IMAGE'} OBJECT_TYPES_RENDER = {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'} @@ -68,20 +68,20 @@ def rna_backup_restore(data, backup): setattr(dt, path[-1], val) -def do_previews(do_objects, do_groups, do_scenes, do_data_intern): +def do_previews(do_objects, do_collections, do_scenes, do_data_intern): import collections # Helpers. RenderContext = collections.namedtuple("RenderContext", ( - "scene", "world", "camera", "lamp", "camera_data", "lamp_data", "image", # All those are names! - "backup_scene", "backup_world", "backup_camera", "backup_lamp", "backup_camera_data", "backup_lamp_data", + "scene", "world", "camera", "light", "camera_data", "light_data", "image", # All those are names! + "backup_scene", "backup_world", "backup_camera", "backup_light", "backup_camera_data", "backup_light_data", )) RENDER_PREVIEW_SIZE = bpy.app.render_preview_size def render_context_create(engine, objects_ignored): if engine == '__SCENE': - backup_scene, backup_world, backup_camera, backup_lamp, backup_camera_data, backup_lamp_data = [()] * 6 + backup_scene, backup_world, backup_camera, backup_light, backup_camera_data, backup_light_data = [()] * 6 scene = bpy.context.screen.scene exclude_props = {('world',), ('camera',), ('tool_settings',), ('preview',)} backup_scene = tuple(rna_backup_gen(scene, exclude_props=exclude_props)) @@ -96,20 +96,20 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): camera.rotation_euler = Euler((1.1635528802871704, 0.0, 0.7853981852531433), 'XYZ') # (66.67, 0.0, 45.0) scene.camera = camera scene.objects.link(camera) - # TODO: add lamp if none found in scene? - lamp = None - lamp_data = None + # TODO: add light if none found in scene? + light = None + light_data = None else: - backup_scene, backup_world, backup_camera, backup_lamp, backup_camera_data, backup_lamp_data = [None] * 6 + backup_scene, backup_world, backup_camera, backup_light, backup_camera_data, backup_light_data = [None] * 6 scene = bpy.data.scenes.new("TEMP_preview_render_scene") world = bpy.data.worlds.new("TEMP_preview_render_world") camera_data = bpy.data.cameras.new("TEMP_preview_render_camera") camera = bpy.data.objects.new("TEMP_preview_render_camera", camera_data) - lamp_data = bpy.data.lamps.new("TEMP_preview_render_lamp", 'SPOT') - lamp = bpy.data.objects.new("TEMP_preview_render_lamp", lamp_data) + light_data = bpy.data.lights.new("TEMP_preview_render_light", 'SPOT') + light = bpy.data.objects.new("TEMP_preview_render_light", light_data) - objects_ignored.add((camera.name, lamp.name)) + objects_ignored.add((camera.name, light.name)) scene.world = world @@ -117,26 +117,14 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): scene.camera = camera scene.objects.link(camera) - lamp.rotation_euler = Euler((0.7853981852531433, 0.0, 1.7453292608261108), 'XYZ') # (45.0, 0.0, 100.0) - lamp_data.falloff_type = 'CONSTANT' - lamp_data.spot_size = 1.0471975803375244 # 60 - scene.objects.link(lamp) - - if engine == 'BLENDER_RENDER': - scene.render.engine = 'BLENDER_RENDER' - scene.render.alpha_mode = 'TRANSPARENT' - - world.use_sky_blend = True - world.horizon_color = 0.9, 0.9, 0.9 - world.zenith_color = 0.5, 0.5, 0.5 - world.ambient_color = 0.1, 0.1, 0.1 - world.light_settings.use_environment_light = True - world.light_settings.environment_energy = 1.0 - world.light_settings.environment_color = 'SKY_COLOR' - elif engine == 'CYCLES': - scene.render.engine = 'CYCLES' - scene.cycles.film_transparent = True - # TODO: define Cycles world? + light.rotation_euler = Euler((0.7853981852531433, 0.0, 1.7453292608261108), 'XYZ') # (45.0, 0.0, 100.0) + light_data.falloff_type = 'CONSTANT' + light_data.spot_size = 1.0471975803375244 # 60 + scene.objects.link(light) + + scene.render.engine = 'CYCLES' + scene.cycles.film_transparent = True + # TODO: define Cycles world? scene.render.image_settings.file_format = 'PNG' scene.render.image_settings.color_depth = '8' @@ -154,9 +142,9 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): image.filepath = scene.render.filepath return RenderContext( - scene.name, world.name if world else None, camera.name, lamp.name if lamp else None, - camera_data.name, lamp_data.name if lamp_data else None, image.name, - backup_scene, backup_world, backup_camera, backup_lamp, backup_camera_data, backup_lamp_data, + scene.name, world.name if world else None, camera.name, light.name if light else None, + camera_data.name, light_data.name if light_data else None, image.name, + backup_scene, backup_world, backup_camera, backup_light, backup_camera_data, backup_light_data, ) def render_context_delete(render_context): @@ -171,8 +159,8 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): scene.camera = None if render_context.camera: scene.objects.unlink(bpy.data.objects[render_context.camera, None]) - if render_context.lamp: - scene.objects.unlink(bpy.data.objects[render_context.lamp, None]) + if render_context.light: + scene.objects.unlink(bpy.data.objects[render_context.light, None]) bpy.data.scenes.remove(scene, do_unlink=True) scene = None else: @@ -213,18 +201,18 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): print("ERROR:", e) success = False - if render_context.lamp: + if render_context.light: try: - lamp = bpy.data.objects[render_context.lamp, None] - if render_context.backup_lamp is None: + light = bpy.data.objects[render_context.light, None] + if render_context.backup_light is None: if scene is not None: - scene.objects.unlink(lamp) - lamp.user_clear() - bpy.data.objects.remove(lamp) - bpy.data.lamps.remove(bpy.data.lamps[render_context.lamp_data, None]) + scene.objects.unlink(light) + light.user_clear() + bpy.data.objects.remove(light) + bpy.data.lights.remove(bpy.data.lights[render_context.light_data, None]) else: - rna_backup_restore(lamp, render_context.backup_lamp) - rna_backup_restore(bpy.data.lamps[render_context.lamp_data, None], render_context.backup_lamp_data) + rna_backup_restore(light, render_context.backup_light) + rna_backup_restore(bpy.data.lights[render_context.light_data, None], render_context.backup_light_data) except Exception as e: print("ERROR:", e) success = False @@ -239,21 +227,10 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): return success - def objects_render_engine_guess(obs): - for obname, libpath in obs: - ob = bpy.data.objects[obname, libpath] - for matslot in ob.material_slots: - mat = matslot.material - if mat and mat.use_nodes and mat.node_tree: - for nd in mat.node_tree.nodes: - if nd.shading_compatibility == {'NEW_SHADING'}: - return 'CYCLES' - return 'BLENDER_RENDER' - def object_bbox_merge(bbox, ob, ob_space, offset_matrix): - # Take group instances into account (including linked one in this case). - if ob.type == 'EMPTY' and ob.dupli_type == 'GROUP': - grp_objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in ob.dupli_group.objects) + # Take collections instances into account (including linked one in this case). + if ob.type == 'EMPTY' and ob.dupli_type == 'COLLECTION': + grp_objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in ob.dupli_group.all_objects) if (len(grp_objects) == 0): ob_bbox = ob.bound_box else: @@ -305,7 +282,7 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): scene = bpy.data.scenes[render_context.scene, None] if objects is not None: camera = bpy.data.objects[render_context.camera, None] - lamp = bpy.data.objects[render_context.lamp, None] if render_context.lamp is not None else None + light = bpy.data.objects[render_context.light, None] if render_context.light is not None else None cos = objects_bbox_calc(camera, objects, offset_matrix) loc, ortho_scale = camera.camera_fit_coords(scene, cos) camera.location = loc @@ -320,9 +297,9 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): max_dist = dist camera.data.clip_start = min_dist / 2 camera.data.clip_end = max_dist * 2 - if lamp: - loc, ortho_scale = lamp.camera_fit_coords(scene, cos) - lamp.location = loc + if light: + loc, ortho_scale = light.camera_fit_coords(scene, cos) + light.location = loc scene.update() bpy.ops.render.render(write_still=True) @@ -343,7 +320,7 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): render_contexts = {} objects_ignored = set() - groups_ignored = set() + collections_ignored = set() prev_scenename = bpy.context.screen.scene.name @@ -360,11 +337,10 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): continue objects = ((root.name, None),) - render_engine = objects_render_engine_guess(objects) - render_context = render_contexts.get(render_engine, None) + render_context = render_contexts.get('CYCLES', None) if render_context is None: - render_context = render_context_create(render_engine, objects_ignored) - render_contexts[render_engine] = render_context + render_context = render_context_create('CYCLES', objects_ignored) + render_contexts['CYCLES'] = render_context scene = bpy.data.scenes[render_context.scene, None] bpy.context.screen.scene = scene @@ -398,30 +374,29 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): if is_rendered is not ...: ob.hide_render = is_rendered - if do_groups: - for grp in ids_nolib(bpy.data.groups): - if grp.name in groups_ignored: + if do_collections: + for grp in ids_nolib(bpy.data.collections): + if grp.name in collections_ignored: continue - # Here too, we do want to keep linked objects members of local group... + # Here too, we do want to keep linked objects members of local collection... objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in grp.objects) - render_engine = objects_render_engine_guess(objects) - render_context = render_contexts.get(render_engine, None) + render_context = render_contexts.get('CYCLES', None) if render_context is None: - render_context = render_context_create(render_engine, objects_ignored) - render_contexts[render_engine] = render_context + render_context = render_context_create('CYCLES', objects_ignored) + render_contexts['CYCLES'] = render_context scene = bpy.data.scenes[render_context.scene, None] bpy.context.screen.scene = scene - bpy.ops.object.group_instance_add(group=grp.name) + bpy.ops.object.collection_instance_add(collection=grp.name) grp_ob = next((ob for ob in scene.objects if ob.dupli_group and ob.dupli_group.name == grp.name)) grp_obname = grp_ob.name scene.update() offset_matrix = Matrix.Translation(grp.dupli_offset).inverted() - preview_render_do(render_context, 'groups', grp.name, objects, offset_matrix) + preview_render_do(render_context, 'collections', grp.name, objects, offset_matrix) scene = bpy.data.scenes[render_context.scene, None] scene.objects.unlink(bpy.data.objects[grp_obname, None]) @@ -462,7 +437,7 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern): print("*NOT* Saving %s, because some error(s) happened while deleting temp render data..." % bpy.data.filepath) -def do_clear_previews(do_objects, do_groups, do_scenes, do_data_intern): +def do_clear_previews(do_objects, do_collections, do_scenes, do_data_intern): if do_data_intern: bpy.ops.wm.previews_clear(id_type=INTERN_PREVIEW_TYPES) @@ -470,8 +445,8 @@ def do_clear_previews(do_objects, do_groups, do_scenes, do_data_intern): for ob in ids_nolib(bpy.data.objects): ob.preview.image_size = (0, 0) - if do_groups: - for grp in ids_nolib(bpy.data.groups): + if do_collections: + for grp in ids_nolib(bpy.data.collections): grp.preview.image_size = (0, 0) if do_scenes: @@ -502,8 +477,8 @@ def main(): help="Do not generate a backup .blend1 file when saving processed ones.") parser.add_argument('--no_scenes', default=True, action="store_false", help="Do not generate/clear previews for scene IDs.") - parser.add_argument('--no_groups', default=True, action="store_false", - help="Do not generate/clear previews for group IDs.") + parser.add_argument('--no_collections', default=True, action="store_false", + help="Do not generate/clear previews for collection IDs.") parser.add_argument('--no_objects', default=True, action="store_false", help="Do not generate/clear previews for object IDs.") parser.add_argument('--no_data_intern', default=True, action="store_false", @@ -518,11 +493,11 @@ def main(): if args.clear: print("clear!") - do_clear_previews(do_objects=args.no_objects, do_groups=args.no_groups, do_scenes=args.no_scenes, + do_clear_previews(do_objects=args.no_objects, do_collections=args.no_collections, do_scenes=args.no_scenes, do_data_intern=args.no_data_intern) else: print("render!") - do_previews(do_objects=args.no_objects, do_groups=args.no_groups, do_scenes=args.no_scenes, + do_previews(do_objects=args.no_objects, do_collections=args.no_collections, do_scenes=args.no_scenes, do_data_intern=args.no_data_intern) # Not really necessary, but better be consistent. diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py index 6312c25065f..a80135a59e1 100644 --- a/release/scripts/modules/bpy/__init__.py +++ b/release/scripts/modules/bpy/__init__.py @@ -39,6 +39,7 @@ from _bpy import ( app, context, data, + msgbus, props, types, ) diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py index 7c5c76ffdbe..6d8ed1c1780 100644 --- a/release/scripts/modules/bpy/ops.py +++ b/release/scripts/modules/bpy/ops.py @@ -145,10 +145,10 @@ class BPyOpsSubModOp: return C_dict, C_exec, C_undo @staticmethod - def _scene_update(context): - scene = context.scene - if scene: # None in background mode - scene.update() + def _view_layer_update(context): + view_layer = context.view_layer + if view_layer: # None in background mode + view_layer.update() else: import bpy for scene in bpy.data.scenes: @@ -180,7 +180,10 @@ class BPyOpsSubModOp: wm = context.window_manager # run to account for any rna values the user changes. - BPyOpsSubModOp._scene_update(context) + # NOTE: We only update active vew layer, since that's what + # operators are supposed to operate on. There might be some + # corner cases when operator need a full scene update though. + BPyOpsSubModOp._view_layer_update(context) if args: C_dict, C_exec, C_undo = BPyOpsSubModOp._parse_args(args) @@ -189,7 +192,7 @@ class BPyOpsSubModOp: ret = op_call(self.idname_py(), None, kw) if 'FINISHED' in ret and context.window_manager == wm: - BPyOpsSubModOp._scene_update(context) + BPyOpsSubModOp._view_layer_update(context) return ret diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 5e5a35b9518..80e48697b2f 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -34,7 +34,6 @@ __all__ = ( "refresh_script_paths", "app_template_paths", "register_class", - "register_module", "register_manual_map", "unregister_manual_map", "register_classes_factory", @@ -50,7 +49,6 @@ __all__ = ( "smpte_from_seconds", "units", "unregister_class", - "unregister_module", "user_resource", ) @@ -166,10 +164,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): for module_name in [ext.module for ext in _user_preferences.addons]: _addon_utils.disable(module_name) - # *AFTER* unregistering all add-ons, otherwise all calls to - # unregister_module() will silently fail (do nothing). - _bpy_types.TypeMap.clear() - def register_module_call(mod): register = getattr(mod, "register", None) if register: @@ -581,8 +575,13 @@ def keyconfig_set(filepath, report=None): try: error_msg = "" with open(filepath, 'r', encoding='utf-8') as keyfile: - exec(compile(keyfile.read(), filepath, "exec"), - {"__file__": filepath}) + exec( + compile(keyfile.read(), filepath, "exec"), + { + "__file__": filepath, + "__name__": "__main__", + } + ) except: import traceback error_msg = traceback.format_exc() @@ -650,58 +649,6 @@ def user_resource(resource_type, path="", create=False): return target_path -def _bpy_module_classes(module, is_registered=False): - typemap_list = _bpy_types.TypeMap.get(module, ()) - i = 0 - while i < len(typemap_list): - cls_weakref = typemap_list[i] - cls = cls_weakref() - - if cls is None: - del typemap_list[i] - else: - if is_registered == cls.is_registered: - yield cls - i += 1 - - -def register_module(module, verbose=False): - if verbose: - print("bpy.utils.register_module(%r): ..." % module) - cls = None - for cls in _bpy_module_classes(module, is_registered=False): - if verbose: - print(" %r" % cls) - try: - register_class(cls) - except: - print("bpy.utils.register_module(): " - "failed to registering class %r" % cls) - import traceback - traceback.print_exc() - if verbose: - print("done.\n") - if cls is None: - raise Exception("register_module(%r): defines no classes" % module) - - -def unregister_module(module, verbose=False): - if verbose: - print("bpy.utils.unregister_module(%r): ..." % module) - for cls in _bpy_module_classes(module, is_registered=True): - if verbose: - print(" %r" % cls) - try: - unregister_class(cls) - except: - print("bpy.utils.unregister_module(): " - "failed to unregistering class %r" % cls) - import traceback - traceback.print_exc() - if verbose: - print("done.\n") - - def register_classes_factory(classes): """ Utility function to create register and unregister functions diff --git a/release/scripts/modules/bpy_extras/__init__.py b/release/scripts/modules/bpy_extras/__init__.py index d2578e1812a..1caef074d43 100644 --- a/release/scripts/modules/bpy_extras/__init__.py +++ b/release/scripts/modules/bpy_extras/__init__.py @@ -29,5 +29,6 @@ __all__ = ( "image_utils", "keyconfig_utils", "mesh_utils", + "node_utils", "view3d_utils", ) diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index e2c2e4c9b93..a0c1c3e5c84 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -52,25 +52,19 @@ def _check_axis_conversion(op): class ExportHelper: - filepath = StringProperty( + filepath: StringProperty( name="File Path", description="Filepath used for exporting the file", maxlen=1024, subtype='FILE_PATH', ) - check_existing = BoolProperty( + check_existing: BoolProperty( name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'}, ) - # needed for mix-ins - order = [ - "filepath", - "check_existing", - ] - # subclasses can override with decorator # True == use ext, False == no ext, None == do nothing. check_extension = True @@ -112,18 +106,13 @@ class ExportHelper: class ImportHelper: - filepath = StringProperty( + filepath: StringProperty( name="File Path", description="Filepath used for importing the file", maxlen=1024, subtype='FILE_PATH', ) - # needed for mix-ins - order = [ - "filepath", - ] - def invoke(self, context, event): context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} @@ -173,11 +162,6 @@ def orientation_helper_factory(name, axis_forward='Y', axis_up='Z'): update=_update_axis_up, ) - members["order"] = [ - "axis_forward", - "axis_up", - ] - return type(name, (object,), members) diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index 0ff6595eca9..ec4db69986c 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -56,6 +56,7 @@ KM_HIERARCHY = [ ('Particle', 'EMPTY', 'WINDOW', []), ('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []), + ('Custom Normals Modal Map', 'EMPTY', 'WINDOW', []), ('Paint Stroke Modal', 'EMPTY', 'WINDOW', []), ('Paint Curve', 'EMPTY', 'WINDOW', []), @@ -99,7 +100,6 @@ KM_HIERARCHY = [ ('SequencerCommon', 'SEQUENCE_EDITOR', 'WINDOW', []), ('SequencerPreview', 'SEQUENCE_EDITOR', 'WINDOW', []), ]), - ('Logic Editor', 'LOGIC_EDITOR', 'WINDOW', []), ('File Browser', 'FILE_BROWSER', 'WINDOW', [ ('File Browser Main', 'FILE_BROWSER', 'WINDOW', []), @@ -122,6 +122,12 @@ KM_HIERARCHY = [ ('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region) ('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint (Draw brush)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint (Fill)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint (Erase)', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Paint Mode', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Sculpt Mode', 'EMPTY', 'WINDOW', []), + ('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []), ]), ('Mask Editing', 'EMPTY', 'WINDOW', []), ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region) @@ -408,3 +414,11 @@ def keyconfig_test(kc): if testEntry(kc, entry): result = True return result + + +# Note, we may eventually replace existing logic with this +# so key configs are always data. +from .keyconfig_utils_experimental import ( + keyconfig_export_as_data, + keyconfig_import_from_data, +) diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils_experimental.py b/release/scripts/modules/bpy_extras/keyconfig_utils_experimental.py new file mode 100644 index 00000000000..cd82460e8e0 --- /dev/null +++ b/release/scripts/modules/bpy_extras/keyconfig_utils_experimental.py @@ -0,0 +1,244 @@ +# ##### 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__ = ( + "keyconfig_export_as_data", + "keyconfig_import_from_data", +) + + +def indent(levels): + return levels * " " + + +def round_float_32(f): + from struct import pack, unpack + return unpack("f", pack("f", f))[0] + + +def repr_f32(f): + f_round = round_float_32(f) + f_str = repr(f) + f_str_frac = f_str.partition(".")[2] + if not f_str_frac: + return f_str + for i in range(1, len(f_str_frac)): + f_test = round(f, i) + f_test_round = round_float_32(f_test) + if f_test_round == f_round: + return "%.*f" % (i, f_test) + return f_str + + +def kmi_args_as_data(kmi): + s = [ + f"\"type\": '{kmi.type}'", + f"\"value\": '{kmi.value}'" + ] + + if kmi.any: + s.append("\"any\": True") + else: + if kmi.shift: + s.append("\"shift\": True") + if kmi.ctrl: + s.append("\"ctrl\": True") + if kmi.alt: + s.append("\"alt\": True") + if kmi.oskey: + s.append("\"oskey\": True") + if kmi.key_modifier and kmi.key_modifier != 'NONE': + s.append(f"\"key_modifier\": '{kmi.key_modifier}'") + + return "{" + ", ".join(s) + "}" + + +def _kmi_properties_to_lines_recursive(level, properties, lines): + from bpy.types import OperatorProperties + + def string_value(value): + if isinstance(value, (str, bool, int)): + return repr(value) + elif isinstance(value, float): + return repr_f32(value) + elif getattr(value, '__len__', False): + return repr(tuple(value)) + raise Exception(f"Export key configuration: can't write {value!r}") + + for pname in properties.bl_rna.properties.keys(): + if pname != "rna_type": + value = getattr(properties, pname) + if isinstance(value, OperatorProperties): + lines_test = [] + _kmi_properties_to_lines_recursive(level + 2, value, lines_test) + if lines_test: + lines.append(f"(") + lines.append(f"\"{pname}\",\n") + lines.append(f"{indent(level + 3)}" "[") + lines.extend(lines_test) + lines.append("],\n") + lines.append(f"{indent(level + 3)}" "),\n" f"{indent(level + 2)}") + del lines_test + elif properties.is_property_set(pname): + value = string_value(value) + lines.append((f"(\"{pname}\", {value:s}),\n" f"{indent(level + 2)}")) + + +def _kmi_properties_to_lines(level, kmi_props, lines): + if kmi_props is None: + return + + lines_test = [f"\"properties\":\n" f"{indent(level + 1)}" "["] + _kmi_properties_to_lines_recursive(level, kmi_props, lines_test) + if len(lines_test) > 1: + lines_test.append("],\n") + lines.extend(lines_test) + + +def _kmi_attrs_or_none(level, kmi): + lines = [] + _kmi_properties_to_lines(level + 1, kmi.properties, lines) + if kmi.active is False: + lines.append(f"{indent(level)}\"active\":" "False,\n") + if not lines: + return None + return "".join(lines) + + +def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False): + # Alternate foramt + + # Generate a list of keymaps to export: + # + # First add all user_modified keymaps (found in keyconfigs.user.keymaps list), + # then add all remaining keymaps from the currently active custom keyconfig. + # + # This will create a final list of keymaps that can be used as a "diff" against + # the default blender keyconfig, recreating the current setup from a fresh blender + # without needing to export keymaps which haven't been edited. + + from .keyconfig_utils import keyconfig_merge + + class FakeKeyConfig: + keymaps = [] + edited_kc = FakeKeyConfig() + for km in wm.keyconfigs.user.keymaps: + if all_keymaps or km.is_user_modified: + edited_kc.keymaps.append(km) + # merge edited keymaps with non-default keyconfig, if it exists + if kc != wm.keyconfigs.default: + export_keymaps = keyconfig_merge(edited_kc, kc) + else: + export_keymaps = keyconfig_merge(edited_kc, edited_kc) + + with open(filepath, "w") as fh: + fw = fh.write + fw("keyconfig_data = \\\n[") + + for km, kc_x in export_keymaps: + km = km.active() + fw("(") + fw(f"\"{km.name:s}\",\n") + fw(f"{indent(2)}" "{") + fw(f"\"space_type\": '{km.space_type:s}'") + fw(f", \"region_type\": '{km.region_type:s}'") + # We can detect from the kind of items. + if km.is_modal: + fw(", \"modal\": True") + fw("},\n") + fw(f"{indent(2)}" "{") + is_modal = km.is_modal + fw(f"\"items\":\n") + fw(f"{indent(3)}[") + for kmi in km.keymap_items: + if is_modal: + kmi_id = kmi.propvalue + else: + kmi_id = kmi.idname + fw(f"(") + kmi_args = kmi_args_as_data(kmi) + kmi_data = _kmi_attrs_or_none(4, kmi) + fw(f"\"{kmi_id:s}\"") + if kmi_data is None: + fw(f", ") + else: + fw(",\n" f"{indent(5)}") + + fw(kmi_args) + if kmi_data is None: + fw(", None),\n") + else: + fw(",\n") + fw(f"{indent(5)}" "{") + fw(kmi_data) + fw(f"{indent(6)}") + fw("},\n" f"{indent(5)}") + fw("),\n") + fw(f"{indent(4)}") + fw("],\n" f"{indent(3)}") + fw("},\n" f"{indent(2)}") + fw("),\n" f"{indent(1)}") + + fw("]\n") + fw("\n\n") + fw("if __name__ == \"__main__\":\n") + fw(" import os\n") + fw(" from bpy_extras.keyconfig_utils import keyconfig_import_from_data\n") + fw(" keyconfig_import_from_data(os.path.splitext(os.path.basename(__file__))[0], keyconfig_data)\n") + + +def keyconfig_import_from_data(name, keyconfig_data): + # Load data in the format defined above. + # + # Runs at load time, keep this fast! + + def kmi_props_setattr(kmi_props, attr, value): + if type(value) is list: + kmi_subprop = getattr(kmi_props, attr) + for subattr, subvalue in value: + kmi_props_setattr(kmi_subprop, subattr, subvalue) + return + + try: + setattr(kmi_props, attr, value) + except AttributeError: + print(f"Warning: property '{attr}' not found in keymap item '{kmi_props.__class__.__name__}'") + except Exception as ex: + print(f"Warning: {ex!r}") + + import bpy + wm = bpy.context.window_manager + kc = wm.keyconfigs.new(name) + del name + + for (km_name, km_args, km_content) in keyconfig_data: + km = kc.keymaps.new(km_name, **km_args) + is_modal = km_args.get("modal", False) + new_fn = getattr(km.keymap_items, "new_modal" if is_modal else "new") + for (kmi_idname, kmi_args, kmi_data) in km_content["items"]: + kmi = new_fn(kmi_idname, **kmi_args) + if kmi_data is not None: + if not kmi_data.get("active", True): + kmi.active = False + kmi_props_data = kmi_data.get("properties", None) + if kmi_props_data is not None: + kmi_props = kmi.properties + for attr, value in kmi_props_data: + kmi_props_setattr(kmi_props, attr, value) diff --git a/release/scripts/modules/bpy_extras/node_utils.py b/release/scripts/modules/bpy_extras/node_utils.py new file mode 100644 index 00000000000..d4c6d5cd45a --- /dev/null +++ b/release/scripts/modules/bpy_extras/node_utils.py @@ -0,0 +1,32 @@ +# ##### 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-80 compliant> + +__all__ = ( + "find_node_input", +) + + +# XXX Names are not unique. Returns the first match. +def find_node_input(node, name): + for input in node.inputs: + if input.name == name: + return input + + return None diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 0a48d99b529..fff73a4285a 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -103,9 +103,9 @@ def add_object_align_init(context, operator): return location * rotation -def object_data_add(context, obdata, operator=None, use_active_layer=True, name=None): +def object_data_add(context, obdata, operator=None, name=None): """ - Add an object using the view context and preference to to initialize the + Add an object using the view context and preference to initialize the location, rotation and layer. :arg context: The context to use. @@ -117,53 +117,31 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name= :arg name: Optional name :type name: string :return: the newly created object in the scene. - :rtype: :class:`bpy.types.ObjectBase` + :rtype: :class:`bpy.types.Object` """ scene = context.scene + layer = context.view_layer + layer_collection = context.layer_collection - # ugh, could be made nicer - for ob in scene.objects: - ob.select = False + for ob in layer.objects: + ob.select_set(action='DESELECT') + + if not layer_collection: + # when there is no collection linked to this view_layer create one + scene_collection = scene.master_collection.collections.new("") + layer_collection = layer.collections.link(scene_collection) + else: + scene_collection = layer_collection.collection if name is None: name = "Object" if obdata is None else obdata.name + obj_act = layer.objects.active obj_new = bpy.data.objects.new(name, obdata) - - base = scene.objects.link(obj_new) - base.select = True - - v3d = None - if context.space_data and context.space_data.type == 'VIEW_3D': - v3d = context.space_data - - if v3d and v3d.local_view: - base.layers_from_view(context.space_data) - - if operator is not None and any(operator.layers): - base.layers = operator.layers - else: - if use_active_layer: - if v3d and v3d.local_view: - base.layers[scene.active_layer] = True - else: - if v3d and not v3d.lock_camera_and_layers: - base.layers = [True if i == v3d.active_layer - else False for i in range(len(v3d.layers))] - else: - base.layers = [True if i == scene.active_layer - else False for i in range(len(scene.layers))] - else: - if v3d: - base.layers_from_view(context.space_data) - - if operator is not None: - operator.layers = base.layers - + scene_collection.objects.link(obj_new) + obj_new.select_set(action='SELECT') obj_new.matrix_world = add_object_align_init(context, operator) - obj_act = scene.objects.active - # XXX # caused because entering edit-mode does not add a empty undo slot! if context.user_preferences.edit.use_enter_edit_mode: @@ -174,8 +152,8 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name= _obdata = bpy.data.meshes.new(name) obj_act = bpy.data.objects.new(_obdata.name, _obdata) obj_act.matrix_world = obj_new.matrix_world - scene.objects.link(obj_act) - scene.objects.active = obj_act + scene_collection.objects.link(obj_act) + layer.objects.active = obj_act bpy.ops.object.mode_set(mode='EDIT') # need empty undo step bpy.ops.ed.undo_push(message="Enter Editmode") @@ -183,11 +161,12 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name= if obj_act and obj_act.mode == 'EDIT' and obj_act.type == obj_new.type: bpy.ops.mesh.select_all(action='DESELECT') + obj_act.select_set(action='SELECT') bpy.ops.object.mode_set(mode='OBJECT') - obj_act.select = True + obj_act.select_set(action='SELECT') scene.update() # apply location - # scene.objects.active = obj_new + # layer.objects.active = obj_new # Match up UV layers, this is needed so adding an object with UV's # doesn't create new layers when there happens to be a naming mis-match. @@ -200,16 +179,14 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name= bpy.ops.object.join() # join into the active. if obdata: bpy.data.meshes.remove(obdata) - # base is freed, set to active object - base = scene.object_bases.active bpy.ops.object.mode_set(mode='EDIT') else: - scene.objects.active = obj_new + layer.objects.active = obj_new if context.user_preferences.edit.use_enter_edit_mode: bpy.ops.object.mode_set(mode='EDIT') - return base + return obj_new class AddObjectHelper: @@ -217,25 +194,19 @@ class AddObjectHelper: if not self.view_align: self.rotation.zero() - view_align = BoolProperty( + view_align: BoolProperty( name="Align to View", default=False, update=view_align_update_callback, ) - location = FloatVectorProperty( + location: FloatVectorProperty( name="Location", subtype='TRANSLATION', ) - rotation = FloatVectorProperty( + rotation: FloatVectorProperty( name="Rotation", subtype='EULER', ) - layers = BoolVectorProperty( - name="Layers", - size=20, - subtype='LAYER', - options={'HIDDEN', 'SKIP_SAVE'}, - ) @classmethod def poll(self, context): @@ -251,7 +222,7 @@ def object_add_grid_scale(context): space_data = context.space_data if space_data and space_data.type == 'VIEW_3D': - return space_data.grid_scale_unit + return space_data.overlay.grid_scale_unit return 1.0 diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 15d92cd6b61..d6d4ecd6fce 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -60,8 +60,8 @@ class Library(bpy_types.ID): # See: readblenentry.c, IDTYPE_FLAGS_ISLINKABLE, # we could make this an attribute in rna. attr_links = ("actions", "armatures", "brushes", "cameras", - "curves", "grease_pencil", "groups", "images", - "lamps", "lattices", "materials", "metaballs", + "curves", "grease_pencil", "collections", "images", + "lights", "lattices", "materials", "metaballs", "meshes", "node_groups", "objects", "scenes", "sounds", "speakers", "textures", "texts", "fonts", "worlds") @@ -96,12 +96,12 @@ class Texture(bpy_types.ID): ) -class Group(bpy_types.ID): +class Collection(bpy_types.ID): __slots__ = () @property def users_dupli_group(self): - """The dupli group this group is used in""" + """The collection instance objects this collection is used in""" import bpy return tuple(obj for obj in bpy.data.objects if self == obj.dupli_group) @@ -118,11 +118,11 @@ class Object(bpy_types.ID): if child.parent == self) @property - def users_group(self): - """The groups this object is in""" + def users_collection(self): + """The collections this object is in""" import bpy - return tuple(group for group in bpy.data.groups - if self in group.objects[:]) + return tuple(collection for collection in bpy.data.collections + if self in collection.objects[:]) @property def users_scene(self): @@ -144,6 +144,21 @@ class WindowManager(bpy_types.ID): finally: self.popmenu_end__internal(popup) + def popover( + self, draw_func, *, + ui_units_x=0, + keymap=None, + ): + import bpy + popup = self.popover_begin__internal( + ui_units_x=ui_units_x, + ) + + try: + draw_func(popup, bpy.context) + finally: + self.popover_end__internal(popup, keymap) + def popup_menu_pie(self, event, draw_func, title="", icon='NONE'): import bpy pie = self.piemenu_begin__internal(title, icon, event) @@ -517,19 +532,6 @@ class Text(bpy_types.ID): self.clear() self.write(string) - @property - def users_logic(self): - """Logic bricks that use this text""" - import bpy - return tuple(obj for obj in bpy.data.objects - if self in [cont.text for cont in obj.game.controllers - if cont.type == 'PYTHON'] - ) - - -# values are module: [(cls, path, line), ...] -TypeMap = {} - class Sound(bpy_types.ID): __slots__ = () @@ -542,59 +544,119 @@ class Sound(bpy_types.ID): class RNAMeta(type): + # TODO(campbell): move to C-API + @property + def is_registered(cls): + return "bl_rna" in cls.__dict__ - def __new__(cls, name, bases, classdict, **args): - result = type.__new__(cls, name, bases, classdict) - if bases and bases[0] is not StructRNA: - from _weakref import ref as ref - module = result.__module__ - # first part of packages only - if "." in module: - module = module[:module.index(".")] +class RNAMetaPropGroup(StructMetaPropGroup, RNAMeta): + pass - TypeMap.setdefault(module, []).append(ref(result)) - return result +# Same as 'Operator' +# only without 'as_keywords' +class Gizmo(StructRNA): + __slots__ = () - @property - def is_registered(cls): - return "bl_rna" in cls.__dict__ + def __getattribute__(self, attr): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if (bl_rna is not None) and (attr in bl_rna.properties): + return getattr(properties, attr) + return super().__getattribute__(attr) + + def __setattr__(self, attr, value): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if (bl_rna is not None) and (attr in bl_rna.properties): + return setattr(properties, attr, value) + return super().__setattr__(attr, value) + def __delattr__(self, attr): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if (bl_rna is not None) and (attr in bl_rna.properties): + return delattr(properties, attr) + return super().__delattr__(attr) -class OrderedDictMini(dict): + from _bpy import ( + _rna_gizmo_target_set_handler as target_set_handler, + _rna_gizmo_target_get_value as target_get_value, + _rna_gizmo_target_set_value as target_set_value, + _rna_gizmo_target_get_range as target_get_range, + ) - def __init__(self, *args): - self.order = [] - dict.__init__(self, args) + # Convenience wrappers around private `_gpu` module. + def draw_custom_shape(self, shape, *, matrix=None, select_id=None): + """ + Draw a shape created form :class:`bpy.types.Gizmo.draw_custom_shape`. - def __setitem__(self, key, val): - dict.__setitem__(self, key, val) - if key not in self.order: - self.order.append(key) + :arg shape: The cached shape to draw. + :type shape: Undefined. + :arg matrix: 4x4 matrix, when not given + :class:`bpy.types.Gizmo.matrix_world` is used. + :type matrix: :class:`mathutils.Matrix` + :arg select_id: The selection id. + Only use when drawing within :class:`bpy.types.Gizmo.draw_select`. + :type select_it: int + """ + import gpu - def __delitem__(self, key): - dict.__delitem__(self, key) - self.order.remove(key) + if matrix is None: + matrix = self.matrix_world + batch, dims = shape -class RNAMetaPropGroup(StructMetaPropGroup, RNAMeta): - pass + # XXX, can we avoid setting the shader every time? + batch.program_set_builtin('3D_UNIFORM_COLOR' if dims == 3 else '2D_UNIFORM_COLOR') + if select_id is not None: + gpu.select.load_id(select_id) + else: + if self.is_highlight: + color = (*self.color_highlight, self.alpha_highlight) + else: + color = (*self.color, self.alpha) + batch.uniform_f32("color", *color) -class OrderedMeta(RNAMeta): + with gpu.matrix.push_pop(): + gpu.matrix.multiply_matrix(matrix) + batch.draw() - def __init__(cls, name, bases, attributes): - if attributes.__class__ is OrderedDictMini: - cls.order = attributes.order + @staticmethod + def new_custom_shape(type, verts): + """ + Create a new shape that can be passed to :class:`bpy.types.Gizmo.draw_custom_shape`. - def __prepare__(name, bases, **kwargs): - return OrderedDictMini() # collections.OrderedDict() + :arg type: The type of shape to create in (POINTS, LINES, TRIS, LINE_STRIP). + :type type: string + :arg verts: Coordinates. + :type verts: sequence of of 2D or 3D coordinates. + :arg display_name: Optional callback that takes the full path, returns the name to display. + :type display_name: Callable that takes a string and returns a string. + :return: The newly created shape. + :rtype: Undefined (it may change). + """ + from _gpu.types import ( + GPUBatch, + GPUVertBuf, + GPUVertFormat, + ) + dims = len(verts[0]) + if dims not in {2, 3}: + raise ValueError("Expected 2D or 3D vertex") + fmt = GPUVertFormat() + pos_id = fmt.attr_add(id="pos", comp_type='F32', len=dims, fetch_mode='FLOAT') + vbo = GPUVertBuf(len=len(verts), format=fmt) + vbo.fill(id=pos_id, data=verts) + batch = GPUBatch(type=type, buf=vbo) + return (batch, dims) # Only defined so operators members can be used by accessing self.order # with doc generation 'self.properties.bl_rna.properties' can fail -class Operator(StructRNA, metaclass=OrderedMeta): +class Operator(StructRNA): __slots__ = () def __getattribute__(self, attr): @@ -626,7 +688,7 @@ class Operator(StructRNA, metaclass=OrderedMeta): if attr not in ignore} -class Macro(StructRNA, metaclass=OrderedMeta): +class Macro(StructRNA): # bpy_types is imported before ops is defined # so we have to do a local import on each run __slots__ = () @@ -666,7 +728,23 @@ class _GenericUI: # ensure menus always get default context operator_context_default = self.layout.operator_context + # Support filtering out by owner + workspace = context.workspace + if workspace.use_filter_by_owner: + owner_names = {owner_id.name for owner_id in workspace.owner_ids} + else: + owner_names = None + for func in draw_ls._draw_funcs: + + # Begin 'owner_id' filter. + if owner_names is not None: + owner_id = getattr(func, "_owner", None) + if owner_id is not None: + if func._owner not in owner_names: + continue + # End 'owner_id' filter. + # so bad menu functions don't stop # the entire menu from drawing try: @@ -682,6 +760,13 @@ class _GenericUI: return draw_funcs + @staticmethod + def _dyn_owner_apply(draw_func): + from _bpy import _bl_owner_id_get + owner_id = _bl_owner_id_get() + if owner_id is not None: + draw_func._owner = owner_id + @classmethod def is_extended(cls): return bool(getattr(cls.draw, "_draw_funcs", None)) @@ -693,6 +778,7 @@ class _GenericUI: takes the same arguments as the menus draw function """ draw_funcs = cls._dyn_ui_initialize() + cls._dyn_owner_apply(draw_func) draw_funcs.append(draw_func) @classmethod @@ -702,6 +788,7 @@ class _GenericUI: the menus draw function """ draw_funcs = cls._dyn_ui_initialize() + cls._dyn_owner_apply(draw_func) draw_funcs.insert(0, draw_func) @classmethod @@ -731,7 +818,8 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): def path_menu(self, searchpaths, operator, *, props_default=None, prop_filepath="filepath", - filter_ext=None, filter_path=None, display_name=None): + filter_ext=None, filter_path=None, display_name=None, + add_operator=None): """ Populate a menu from a list of paths. @@ -777,12 +865,16 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): files.sort() + col = layout.column(align=True) + for f, filepath in files: # Intentionally pass the full path to 'display_name' callback, # since the callback may want to use part a directory in the name. - props = layout.operator( + row = col.row(align=True) + name = display_name(filepath) if display_name else bpy.path.display_name(f) + props = row.operator( operator, - text=display_name(filepath) if display_name else bpy.path.display_name(f), + text=name, translate=False, ) @@ -794,6 +886,24 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): if operator == "script.execute_preset": props.menu_idname = self.bl_idname + if add_operator: + props = row.operator(add_operator, text="", icon='ZOOMOUT') + props.name = name + props.remove_name = True + + if add_operator: + wm = bpy.data.window_managers[0] + + layout.separator() + row = layout.row() + + sub = row.row() + sub.emboss = 'NORMAL' + sub.prop(wm, "preset_name", text="") + + props = row.operator(add_operator, text="", icon='ZOOMIN') + props.name = wm.preset_name + def draw_preset(self, context): """ Define these on the subclass: @@ -801,23 +911,27 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): - preset_subdir (string) Optionally: + - preset_add_operator (string) - preset_extensions (set of strings) - preset_operator_defaults (dict of keyword args) """ import bpy ext_valid = getattr(self, "preset_extensions", {".py", ".xml"}) props_default = getattr(self, "preset_operator_defaults", None) + add_operator = getattr(self, "preset_add_operator", None) self.path_menu(bpy.utils.preset_paths(self.preset_subdir), self.preset_operator, props_default=props_default, - filter_ext=lambda ext: ext.lower() in ext_valid) + filter_ext=lambda ext: ext.lower() in ext_valid, + add_operator=add_operator) @classmethod def draw_collapsible(cls, context, layout): # helper function for (optionally) collapsed header menus # only usable within headers if context.area.show_menus: - cls.draw_menus(layout, context) + # Align menus to space them closely. + cls.draw_menus(layout.row(align=True), context) else: layout.menu(cls.__name__, icon='COLLAPSEMENU') diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py index de8da450125..35bae1e69b7 100644 --- a/release/scripts/modules/keyingsets_utils.py +++ b/release/scripts/modules/keyingsets_utils.py @@ -153,8 +153,10 @@ def get_transform_generators_base_info(data): # no path in this case path = "" - # data on ID-blocks directly should get grouped by the KeyingSet - grouping = None + # transform data on ID-blocks directly should get grouped under a + # hardcoded label ("Object Transforms") so that they get grouped + # consistently when keyframed directly + grouping = "Object Transforms" else: # get the path to the ID-block path = data.path_from_id() diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py index e50922593de..0d17c11456e 100644 --- a/release/scripts/modules/rna_prop_ui.py +++ b/release/scripts/modules/rna_prop_ui.py @@ -129,14 +129,25 @@ def draw(layout, context, context_member, property_type, use_edit=True): props.data_path = context_member del row + show_developer_ui = context.user_preferences.view.show_developer_ui rna_properties = {prop.identifier for prop in rna_item.bl_rna.properties if prop.is_runtime} if items else None + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) + for key, val in items: if key == '_RNA_UI': continue - row = layout.row() + is_rna = (key in rna_properties) + + # only show API defined for developers + if is_rna and not show_developer_ui: + continue + to_dict = getattr(val, "to_dict", None) to_list = getattr(val, "to_list", None) @@ -150,19 +161,20 @@ def draw(layout, context, context_member, property_type, use_edit=True): else: val_draw = val + row = flow.row(align=True) box = row.box() if use_edit: split = box.split(percentage=0.75) - row = split.row() + row = split.row(align=True) else: - row = box.row() + row = box.row(align=True) - row.label(text=key, translate=False) + row.alignment = 'RIGHT' - # explicit exception for arrays - is_rna = (key in rna_properties) + row.label(text=key, translate=False) + # explicit exception for arrays. if to_dict or to_list: row.label(text=val_draw, translate=False) else: @@ -181,6 +193,8 @@ def draw(layout, context, context_member, property_type, use_edit=True): else: row.label(text="API Defined") + del flow + class PropertyPanel: """ diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py index e447d8a4dc5..53b3197fca3 100644 --- a/release/scripts/modules/sys_info.py +++ b/release/scripts/modules/sys_info.py @@ -185,14 +185,19 @@ def write_sysinfo(filepath): output.write("version:\t%r\n" % (bgl.glGetString(bgl.GL_VERSION))) output.write("extensions:\n") - glext = sorted(bgl.glGetString(bgl.GL_EXTENSIONS).split()) + limit = bgl.Buffer(bgl.GL_INT, 1) + bgl.glGetIntegerv(bgl.GL_NUM_EXTENSIONS, limit) + + glext = [] + for i in range(limit[0]): + glext.append(bgl.glGetStringi(bgl.GL_EXTENSIONS, i)) + + glext = sorted(glext) + for l in glext: output.write("\t%s\n" % l) output.write(title("Implementation Dependent OpenGL Limits")) - limit = bgl.Buffer(bgl.GL_INT, 1) - bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_UNITS, limit) - output.write("Maximum Fixed Function Texture Units:\t%d\n" % limit[0]) bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_VERTICES, limit) output.write("Maximum DrawElements Vertices:\t%d\n" % limit[0]) bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_INDICES, limit) diff --git a/release/scripts/presets/interface_theme/24x_blues.xml b/release/scripts/presets/interface_theme/24x_blues.xml index 36cfeeb5980..18b866eeb0f 100644 --- a/release/scripts/presets/interface_theme/24x_blues.xml +++ b/release/scripts/presets/interface_theme/24x_blues.xml @@ -253,7 +253,7 @@ text_keyframe="#ddd700" camera="#000000" empty="#000000" - lamp="#00000028" + light="#00000028" speaker="#000000" vertex="#000000" vertex_select="#ff8500" diff --git a/release/scripts/presets/interface_theme/back_to_black.xml b/release/scripts/presets/interface_theme/back_to_black.xml index 1636f5b5cf6..464625d0ba5 100644 --- a/release/scripts/presets/interface_theme/back_to_black.xml +++ b/release/scripts/presets/interface_theme/back_to_black.xml @@ -253,7 +253,7 @@ text_keyframe="#ddd700" camera="#535353" empty="#535353" - lamp="#fff0d328" + light="#fff0d328" speaker="#535353" vertex="#72cfdd" vertex_select="#ff8500" diff --git a/release/scripts/presets/interface_theme/blender_24x.xml b/release/scripts/presets/interface_theme/blender_24x.xml index 818e557adf0..d0459e02115 100644 --- a/release/scripts/presets/interface_theme/blender_24x.xml +++ b/release/scripts/presets/interface_theme/blender_24x.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#00000028" + light="#00000028" speaker="#000000" camera="#000000" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/blender_27x.xml b/release/scripts/presets/interface_theme/blender_27x.xml new file mode 100644 index 00000000000..db9d042ae55 --- /dev/null +++ b/release/scripts/presets/interface_theme/blender_27x.xml @@ -0,0 +1,1242 @@ +<bpy> + <Theme> + <user_interface> + <ThemeUserInterface menu_shadow_fac="0.5" + menu_shadow_width="12" + icon_file="" + icon_alpha="1" + icon_saturation="1" + widget_emboss="#ffffff05" + editor_outline="#3f3f3f" + axis_x="#dc0000" + axis_y="#00dc00" + axis_z="#0000dc" + manipulator_hi="#ffffff" + manipulator_primary="#deff0d" + manipulator_secondary="#00ffff" + manipulator_a="#177f17" + manipulator_b="#7f1717"> + <wcol_regular> + <ThemeWidgetColors outline="#191919" + inner="#999999ff" + inner_sel="#646464ff" + item="#191919ff" + text="#000000" + text_sel="#ffffff" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_regular> + <wcol_tool> + <ThemeWidgetColors outline="#191919" + inner="#999999ff" + inner_sel="#646464ff" + item="#191919ff" + text="#000000" + text_sel="#ffffff" + show_shaded="TRUE" + shadetop="15" + shadedown="-15" + roundness="0.4"> + </ThemeWidgetColors> + </wcol_tool> + <wcol_toolbar_item> + <ThemeWidgetColors outline="#000000" + inner="#464646ff" + inner_sel="#ccccccff" + item="#000000ff" + text="#ffffff" + text_sel="#333333" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.6"> + </ThemeWidgetColors> + </wcol_toolbar_item> + <wcol_radio> + <ThemeWidgetColors outline="#000000" + inner="#464646ff" + inner_sel="#5680c2ff" + item="#ffffffff" + text="#ffffff" + text_sel="#000000" + show_shaded="TRUE" + shadetop="15" + shadedown="-15" + roundness="0.4"> + </ThemeWidgetColors> + </wcol_radio> + <wcol_text> + <ThemeWidgetColors outline="#191919" + inner="#999999ff" + inner_sel="#999999ff" + item="#5a5a5aff" + text="#000000" + text_sel="#ffffff" + show_shaded="TRUE" + shadetop="0" + shadedown="25" + roundness="0.4"> + </ThemeWidgetColors> + </wcol_text> + <wcol_option> + <ThemeWidgetColors outline="#000000" + inner="#464646ff" + inner_sel="#464646ff" + item="#ffffffff" + text="#000000" + text_sel="#ffffff" + show_shaded="TRUE" + shadetop="15" + shadedown="-15" + roundness="0.666666"> + </ThemeWidgetColors> + </wcol_option> + <wcol_toggle> + <ThemeWidgetColors outline="#191919" + inner="#999999ff" + inner_sel="#646464ff" + item="#191919ff" + text="#000000" + text_sel="#ffffff" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_toggle> + <wcol_num> + <ThemeWidgetColors outline="#191919" + inner="#b4b4b4ff" + inner_sel="#999999ff" + item="#5a5a5aff" + text="#000000" + text_sel="#ffffff" + show_shaded="TRUE" + shadetop="-20" + shadedown="0" + roundness="1"> + </ThemeWidgetColors> + </wcol_num> + <wcol_numslider> + <ThemeWidgetColors outline="#191919" + inner="#b4b4b4ff" + inner_sel="#999999ff" + item="#808080ff" + text="#000000" + text_sel="#ffffff" + show_shaded="TRUE" + shadetop="-20" + shadedown="0" + roundness="1"> + </ThemeWidgetColors> + </wcol_numslider> + <wcol_box> + <ThemeWidgetColors outline="#191919" + inner="#808080ff" + inner_sel="#646464ff" + item="#191919ff" + text="#000000" + text_sel="#ffffff" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.4"> + </ThemeWidgetColors> + </wcol_box> + <wcol_menu> + <ThemeWidgetColors outline="#000000" + inner="#464646ff" + inner_sel="#464646ff" + item="#ffffffff" + text="#ffffff" + text_sel="#cccccc" + show_shaded="TRUE" + shadetop="15" + shadedown="-15" + roundness="0.4"> + </ThemeWidgetColors> + </wcol_menu> + <wcol_pulldown> + <ThemeWidgetColors outline="#000000" + inner="#3f3f3fff" + inner_sel="#5680c2ff" + item="#ffffffff" + text="#000000" + text_sel="#000000" + show_shaded="FALSE" + shadetop="25" + shadedown="-20" + roundness="0.4"> + </ThemeWidgetColors> + </wcol_pulldown> + <wcol_menu_back> + <ThemeWidgetColors outline="#000000" + inner="#191919e6" + inner_sel="#2d2d2de6" + item="#646464ff" + text="#a0a0a0" + text_sel="#ffffff" + show_shaded="FALSE" + shadetop="25" + shadedown="-20" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_menu_back> + <wcol_pie_menu> + <ThemeWidgetColors outline="#0a0a0a" + inner="#191919e6" + inner_sel="#8c8c8cff" + item="#2d2d2de6" + text="#a0a0a0" + text_sel="#ffffff" + show_shaded="TRUE" + shadetop="10" + shadedown="-10" + roundness="1"> + </ThemeWidgetColors> + </wcol_pie_menu> + <wcol_tooltip> + <ThemeWidgetColors outline="#000000" + inner="#191919e6" + inner_sel="#2d2d2de6" + item="#646464ff" + text="#ffffff" + text_sel="#ffffff" + show_shaded="FALSE" + shadetop="25" + shadedown="-20" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_tooltip> + <wcol_menu_item> + <ThemeWidgetColors outline="#000000" + inner="#00000000" + inner_sel="#5680c2ff" + item="#acacac80" + text="#ffffff" + text_sel="#000000" + show_shaded="TRUE" + shadetop="38" + shadedown="0" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_menu_item> + <wcol_scroll> + <ThemeWidgetColors outline="#323232" + inner="#505050b4" + inner_sel="#646464b4" + item="#808080ff" + text="#000000" + text_sel="#ffffff" + show_shaded="TRUE" + shadetop="5" + shadedown="-5" + roundness="1"> + </ThemeWidgetColors> + </wcol_scroll> + <wcol_progress> + <ThemeWidgetColors outline="#000000" + inner="#bebebeff" + inner_sel="#646464b4" + item="#808080ff" + text="#000000" + text_sel="#ffffff" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_progress> + <wcol_list_item> + <ThemeWidgetColors outline="#000000" + inner="#00000000" + inner_sel="#5680c2ff" + item="#5a5a5aff" + text="#000000" + text_sel="#ffffff" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.4"> + </ThemeWidgetColors> + </wcol_list_item> + <wcol_state> + <ThemeWidgetStateColors inner_anim="#73be4c" + inner_anim_sel="#5aa633" + inner_key="#f0eb64" + inner_key_sel="#d7d34b" + inner_driven="#b400ff" + inner_driven_sel="#9900e6" + inner_overridden="#000000" + inner_overridden_sel="#000000" + blend="0.5"> + </ThemeWidgetStateColors> + </wcol_state> + <wcol_tab> + <ThemeWidgetColors outline="#3c3c3c" + inner="#535353ff" + inner_sel="#727272ff" + item="#5a5a5aff" + text="#000000" + text_sel="#000000" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_tab> + </ThemeUserInterface> + </user_interface> + <view_3d> + <ThemeView3D grid="#404040" + clipping_border_3d="#313131ff" + wire="#000000" + wire_edit="#000000" + gp_vertex="#000000" + gp_vertex_select="#ff8500" + gp_vertex_size="3" + text_grease_pencil="#b5e61d" + object_selected="#f15800" + object_active="#ffaa40" + text_keyframe="#ddd700" + camera="#000000" + empty="#000000" + light="#00000028" + speaker="#000000" + vertex="#000000" + vertex_select="#ff8500" + vertex_size="3" + vertex_bevel="#00a5ff" + vertex_unreferenced="#000000" + edge_select="#ffa000" + edge_seam="#db2512" + edge_sharp="#00ffff" + edge_crease="#cc0099" + edge_bevel="#00a5ff" + edge_facesel="#4b4b4b" + freestyle_edge_mark="#7fff7f" + face="#00000012" + face_select="#ff85003c" + face_dot="#ff8500" + facedot_size="4" + freestyle_face_mark="#7fff7f33" + nurb_uline="#909000" + nurb_vline="#803060" + nurb_sel_uline="#f0ff40" + nurb_sel_vline="#f090a0" + act_spline="#db2512" + handle_free="#000000" + handle_auto="#909000" + handle_vect="#409030" + handle_sel_vect="#40c030" + handle_align="#803060" + handle_sel_free="#000000" + handle_sel_auto="#f0ff40" + handle_sel_align="#f090a0" + lastsel_point="#ffffff" + extra_edge_len="#200000" + extra_edge_angle="#000000" + extra_face_angle="#000080" + extra_face_area="#002000" + editmesh_active="#ffffff80" + normal="#22dddd" + vertex_normal="#2361dd" + split_normal="#dd23dd" + bone_pose="#50c8ff" + bone_pose_active="#8cffff" + bone_solid="#c8c8c8" + bundle_solid="#c8c8c8" + camera_path="#000000" + skin_root="#b44d4d" + view_overlay="#000000" + transform="#ffffff" + frame_current="#60c040" + paint_curve_handle="#7fff7f7f" + paint_curve_pivot="#ff7f7f7f" + outline_width="1"> + <space> + <ThemeSpaceGradient title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#72727280" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <gradients> + <ThemeGradientColors show_grad="FALSE" + gradient="#000000" + high_gradient="#393939"> + </ThemeGradientColors> + </gradients> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGradient> + </space> + </ThemeView3D> + </view_3d> + <graph_editor> + <ThemeGraphEditor grid="#5e5e5e" + frame_current="#60c040" + window_sliders="#969696" + channels_region="#707070" + dopesheet_channel="#52606e" + dopesheet_subchannel="#7c8996" + channel_group="#4f6549" + active_channels_group="#87b17d" + vertex="#000000" + vertex_select="#ff8500" + vertex_size="6" + vertex_bevel="#000000" + vertex_unreferenced="#000000" + handle_free="#000000" + handle_auto="#909000" + handle_vect="#409030" + handle_sel_vect="#40c030" + handle_align="#803060" + handle_sel_free="#000000" + handle_sel_auto="#f0ff40" + handle_sel_align="#f090a0" + handle_auto_clamped="#994030" + handle_sel_auto_clamped="#f0af90" + lastsel_point="#ffffff" + handle_vertex="#000000" + handle_vertex_select="#ff8500" + handle_vertex_size="5"> + <space> + <ThemeSpaceGeneric back="#6b6b6b" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + <space_list> + <ThemeSpaceListGeneric list="#666666" + list_title="#000000" + list_text="#000000" + list_text_hi="#ffffff"> + </ThemeSpaceListGeneric> + </space_list> + </ThemeGraphEditor> + </graph_editor> + <file_browser> + <ThemeFileBrowser selected_file="#ff8c19"> + <space> + <ThemeSpaceGeneric back="#4c4c4c" + title="#000000" + text="#fafafa" + text_hi="#0f0f0f" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeFileBrowser> + </file_browser> + <nla_editor> + <ThemeNLAEditor grid="#5e5e5e" + view_sliders="#969696" + active_action="#cc701a66" + active_action_unset="#9987614d" + strips="#0c0a0a" + strips_selected="#ff8c00" + transition_strips="#1c2630" + transition_strips_selected="#2e75db" + meta_strips="#332642" + meta_strips_selected="#692196" + sound_strips="#2b3d3d" + sound_strips_selected="#1f7a7a" + tweak="#4df31a" + tweak_duplicate="#d90000" + keyframe_border="#000000ff" + keyframe_border_selected="#000000ff" + frame_current="#60c040"> + <space> + <ThemeSpaceGeneric back="#6b6b6b" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + <space_list> + <ThemeSpaceListGeneric list="#666666" + list_title="#000000" + list_text="#000000" + list_text_hi="#ffffff"> + </ThemeSpaceListGeneric> + </space_list> + </ThemeNLAEditor> + </nla_editor> + <dopesheet_editor> + <ThemeDopeSheet grid="#5e5e5e" + frame_current="#60c040" + value_sliders="#000000" + view_sliders="#969696" + dopesheet_channel="#52606e" + dopesheet_subchannel="#7c8996" + channels="#707070" + channels_selected="#60c040" + channel_group="#4f6549" + active_channels_group="#87b17d" + long_key="#0c0a0a" + long_key_selected="#ff8c00" + keyframe="#e8e8e8" + keyframe_selected="#ffbe32" + keyframe_extreme="#e8b3cc" + keyframe_extreme_selected="#f28080" + keyframe_breakdown="#b3dbe8" + keyframe_breakdown_selected="#54bfed" + keyframe_jitter="#94e575" + keyframe_jitter_selected="#61c042" + keyframe_border="#000000ff" + keyframe_border_selected="#000000ff" + keyframe_scale_factor="1" + summary="#cc701a66"> + <space> + <ThemeSpaceGeneric back="#6b6b6b" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + <space_list> + <ThemeSpaceListGeneric list="#666666" + list_title="#000000" + list_text="#000000" + list_text_hi="#ffffff"> + </ThemeSpaceListGeneric> + </space_list> + </ThemeDopeSheet> + </dopesheet_editor> + <image_editor> + <ThemeImageEditor gp_vertex="#000000" + gp_vertex_select="#ff8500" + gp_vertex_size="3" + vertex="#000000" + vertex_select="#ff8500" + vertex_size="3" + vertex_bevel="#000000" + vertex_unreferenced="#000000" + face="#ffffff0a" + face_select="#ff85003c" + face_dot="#ff8500" + facedot_size="3" + freestyle_face_mark="#00000000" + editmesh_active="#ffffff80" + wire_edit="#c0c0c0" + edge_select="#ff8500" + scope_back="#0000004c" + preview_stitch_face="#7f7f0033" + preview_stitch_edge="#ff00ff33" + preview_stitch_vert="#0000ff33" + preview_stitch_stitchable="#00ff00ff" + preview_stitch_unstitchable="#ff0000ff" + preview_stitch_active="#00000000" + uv_shadow="#707070ff" + uv_others="#606060ff" + frame_current="#60c040" + metadatabg="#000000" + metadatatext="#ffffff" + handle_free="#000000" + handle_auto="#909000" + handle_align="#803060" + handle_sel_free="#000000" + handle_sel_auto="#f0ff40" + handle_sel_align="#f090a0" + handle_auto_clamped="#000000" + handle_sel_auto_clamped="#000000" + handle_vertex="#000000" + handle_vertex_select="#ffff00" + handle_vertex_size="5" + paint_curve_handle="#7fff7f7f" + paint_curve_pivot="#ff7f7f7f"> + <space> + <ThemeSpaceGeneric back="#353535" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#72727280" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeImageEditor> + </image_editor> + <sequence_editor> + <ThemeSequenceEditor gp_vertex="#000000" + gp_vertex_select="#ff8500" + gp_vertex_size="3" + grid="#404040" + window_sliders="#a0a0a0" + movie_strip="#516987" + movieclip_strip="#20208f" + image_strip="#6d5881" + scene_strip="#4e983e" + audio_strip="#2e8f8f" + effect_strip="#a9547c" + transition_strip="#a25f6f" + meta_strip="#6d9183" + text_strip="#a29700" + frame_current="#60c040" + keyframe="#ff8500" + draw_action="#50c8ff" + preview_back="#000000" + metadatabg="#000000" + metadatatext="#ffffff"> + <space> + <ThemeSpaceGeneric back="#747474" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#72727280" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeSequenceEditor> + </sequence_editor> + <properties> + <ThemeProperties> + <space> + <ThemeSpaceGeneric back="#727272" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeProperties> + </properties> + <text_editor> + <ThemeTextEditor line_numbers_background="#404040" + selected_text="#c67777" + cursor="#ff0000" + syntax_builtin="#800050" + syntax_symbols="#4c4c4c" + syntax_special="#5f5f00" + syntax_preprocessor="#32008c" + syntax_reserved="#8c3c00" + syntax_comment="#006432" + syntax_string="#640000" + syntax_numbers="#0000c8"> + <space> + <ThemeSpaceGeneric back="#999999" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeTextEditor> + </text_editor> + <node_editor> + <ThemeNodeEditor gp_vertex="#000000" + gp_vertex_select="#ff8500" + gp_vertex_size="3" + node_selected="#f15800" + node_active="#ffaa40" + wire="#000000" + wire_inner="#737373" + wire_select="#ffffff" + selected_text="#7f7070" + node_backdrop="#9b9b9ba0" + converter_node="#686a75" + color_node="#6c696f" + group_node="#69756e" + group_socket_node="#dfca35" + frame_node="#9b9b9ba0" + matte_node="#977474" + distor_node="#749797" + noodle_curving="5" + input_node="#646464" + output_node="#646464" + filter_node="#6c696f" + vector_node="#6c696f" + texture_node="#6c696f" + shader_node="#6c696f" + script_node="#6c696f" + pattern_node="#6c696f" + layout_node="#6c696f"> + <space> + <ThemeSpaceGeneric back="#393939" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#72727280" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + <space_list> + <ThemeSpaceListGeneric list="#a5a5a5" + list_title="#000000" + list_text="#000000" + list_text_hi="#ffffff"> + </ThemeSpaceListGeneric> + </space_list> + </ThemeNodeEditor> + </node_editor> + <outliner> + <ThemeOutliner match="#337f33" + selected_highlight="#82878c"> + <space> + <ThemeSpaceGeneric back="#727272" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeOutliner> + </outliner> + <info> + <ThemeInfo info_selected="#6080ff" + info_selected_text="#ffffff" + info_error="#dc0000" + info_error_text="#000000" + info_warning="#dc8060" + info_warning_text="#000000" + info_info="#00aa00" + info_info_text="#000000" + info_debug="#c4c4c4" + info_debug_text="#000000"> + <space> + <ThemeSpaceGeneric back="#727272" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeInfo> + </info> + <user_preferences> + <ThemeUserPreferences> + <space> + <ThemeSpaceGeneric back="#727272" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeUserPreferences> + </user_preferences> + <console> + <ThemeConsole line_output="#6080ff" + line_input="#ffffff" + line_info="#00aa00" + line_error="#dc6060" + cursor="#dc6060" + select="#ffffff30"> + <space> + <ThemeSpaceGeneric back="#000000" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#727272ff" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeConsole> + </console> + <clip_editor> + <ThemeClipEditor gp_vertex="#000000" + gp_vertex_select="#ff8500" + gp_vertex_size="3" + marker_outline="#000000" + marker="#7f7f00" + active_marker="#ffffff" + selected_marker="#ffff00" + disabled_marker="#7f0000" + locked_marker="#7f7f7f" + path_before="#ff0000" + path_after="#0000ff" + frame_current="#60c040" + strips="#0c0a0a" + strips_selected="#ff8c00" + handle_free="#000000" + handle_auto="#909000" + handle_align="#803060" + handle_sel_free="#000000" + handle_sel_auto="#f0ff40" + handle_sel_align="#f090a0" + handle_auto_clamped="#000000" + handle_sel_auto_clamped="#000000" + handle_vertex="#000000" + handle_vertex_select="#ffff00" + handle_vertex_size="5"> + <space> + <ThemeSpaceGeneric back="#393939" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#72727280" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000019" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + <space_list> + <ThemeSpaceListGeneric list="#666666" + list_title="#000000" + list_text="#000000" + list_text_hi="#ffffff"> + </ThemeSpaceListGeneric> + </space_list> + </ThemeClipEditor> + </clip_editor> + <topbar> + <ThemeTopBar> + <space> + <ThemeSpaceGeneric back="#727272" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#535353ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#72727280" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000000" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeTopBar> + </topbar> + <statusbar> + <ThemeStatusBar> + <space> + <ThemeSpaceGeneric back="#393939" + title="#000000" + text="#000000" + text_hi="#ffffff" + header="#727272ff" + header_text="#000000" + header_text_hi="#ffffff" + button="#72727280" + button_title="#000000" + button_text="#000000" + button_text_hi="#ffffff" + tab_active="#727272" + tab_inactive="#535353" + tab_back="#404040ff" + tab_outline="#3c3c3c"> + <panelcolors> + <ThemePanelColors header="#00000019" + back="#72727280" + sub_back="#00000000" + show_header="FALSE" + show_back="FALSE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeStatusBar> + </statusbar> + <bone_color_sets> + <ThemeBoneColorSet normal="#9a0000" + select="#bd1111" + active="#f70a0a" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#f74018" + select="#f66913" + active="#fa9900" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#1e9109" + select="#59b70b" + active="#83ef1d" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#0a3694" + select="#3667df" + active="#5ec1ef" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#a9294e" + select="#c1416a" + active="#f05d91" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#430c78" + select="#543aa3" + active="#8764d5" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#24785a" + select="#3c9579" + active="#6fb6ab" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#4b707c" + select="#6a8691" + active="#9bc2cd" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#f4c90c" + select="#eec236" + active="#f3ff00" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#1e2024" + select="#484c56" + active="#ffffff" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#6f2f6a" + select="#9845be" + active="#d330d6" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#6c8e22" + select="#7fb022" + active="#bbef5b" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#8d8d8d" + select="#b0b0b0" + active="#dedede" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#834326" + select="#8b5811" + active="#bd6a11" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#08310e" + select="#1c430b" + active="#34622b" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#000000" + select="#000000" + active="#000000" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#000000" + select="#000000" + active="#000000" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#000000" + select="#000000" + active="#000000" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#000000" + select="#000000" + active="#000000" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + <ThemeBoneColorSet normal="#000000" + select="#000000" + active="#000000" + show_colored_constraints="FALSE"> + </ThemeBoneColorSet> + </bone_color_sets> + </Theme> + <ThemeStyle> + <panel_title> + <ThemeFontStyle points="12" + font_kerning_style="FITTED" + shadow="1" + shadow_offset_x="0" + shadow_offset_y="-1" + shadow_alpha="0.15" + shadow_value="1"> + </ThemeFontStyle> + </panel_title> + <widget_label> + <ThemeFontStyle points="11" + font_kerning_style="FITTED" + shadow="3" + shadow_offset_x="0" + shadow_offset_y="-1" + shadow_alpha="0.15" + shadow_value="1"> + </ThemeFontStyle> + </widget_label> + <widget> + <ThemeFontStyle points="11" + font_kerning_style="FITTED" + shadow="0" + shadow_offset_x="0" + shadow_offset_y="0" + shadow_alpha="0.25" + shadow_value="0"> + </ThemeFontStyle> + </widget> + </ThemeStyle> +</bpy> diff --git a/release/scripts/presets/interface_theme/dark_blue_gradient.xml b/release/scripts/presets/interface_theme/dark_blue_gradient.xml index d226f8531b2..589aeab3a50 100644 --- a/release/scripts/presets/interface_theme/dark_blue_gradient.xml +++ b/release/scripts/presets/interface_theme/dark_blue_gradient.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#00000028" + light="#00000028" speaker="#000000" camera="#000000" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/default++.xml b/release/scripts/presets/interface_theme/default++.xml index 413fbc1aa71..3599a094381 100644 --- a/release/scripts/presets/interface_theme/default++.xml +++ b/release/scripts/presets/interface_theme/default++.xml @@ -253,7 +253,7 @@ text_keyframe="#ddd700" camera="#000000" empty="#000000" - lamp="#00000028" + light="#00000028" speaker="#000000" vertex="#000000" vertex_select="#ff8500" diff --git a/release/scripts/presets/interface_theme/elsyiun.xml b/release/scripts/presets/interface_theme/elsyiun.xml index b9292856fe9..51af13a6009 100644 --- a/release/scripts/presets/interface_theme/elsyiun.xml +++ b/release/scripts/presets/interface_theme/elsyiun.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#00000028" + light="#00000028" speaker="#000000" camera="#000000" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/flatty_light.xml b/release/scripts/presets/interface_theme/flatty_light.xml index c89cbd92ca0..497b6575731 100644 --- a/release/scripts/presets/interface_theme/flatty_light.xml +++ b/release/scripts/presets/interface_theme/flatty_light.xml @@ -5,10 +5,17 @@ menu_shadow_width="4" icon_file="" icon_alpha="1" + icon_saturation="0.3" widget_emboss="#00000005" - axis_x="#dc0000" - axis_y="#00dc00" - axis_z="#0000dc"> + editor_outline="#313338" + axis_x="#ff3352" + axis_y="#8bdc00" + axis_z="#046bdc" + manipulator_hi="#ffffff" + manipulator_primary="#ffd842" + manipulator_secondary="#43c2ff" + manipulator_a="#2b9757" + manipulator_b="#c43164"> <wcol_regular> <ThemeWidgetColors outline="#9d9d9d" inner="#b3b3b3ff" @@ -18,7 +25,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="0" - shadedown="-5"> + shadedown="-5" + roundness="0.5"> </ThemeWidgetColors> </wcol_regular> <wcol_tool> @@ -30,9 +38,23 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="0" - shadedown="-5"> + shadedown="-5" + roundness="0.5"> </ThemeWidgetColors> </wcol_tool> + <wcol_toolbar_item> + <ThemeWidgetColors outline="#808080" + inner="#b3b3b3ff" + inner_sel="#dbdbdbff" + item="#1a1a1aff" + text="#1a1a1a" + text_sel="#000000" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.5"> + </ThemeWidgetColors> + </wcol_toolbar_item> <wcol_radio> <ThemeWidgetColors outline="#4d4d4d" inner="#464646ff" @@ -42,7 +64,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="5" - shadedown="-5"> + shadedown="-5" + roundness="0.5"> </ThemeWidgetColors> </wcol_radio> <wcol_text> @@ -54,11 +77,12 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="-8" - shadedown="0"> + shadedown="0" + roundness="0.5"> </ThemeWidgetColors> </wcol_text> <wcol_option> - <ThemeWidgetColors outline="#999999" + <ThemeWidgetColors outline="#333333" inner="#434343ff" inner_sel="#5680c2ff" item="#ffffffff" @@ -66,11 +90,12 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="0" - shadedown="-15"> + shadedown="-15" + roundness="0.5"> </ThemeWidgetColors> </wcol_option> <wcol_toggle> - <ThemeWidgetColors outline="#808080" + <ThemeWidgetColors outline="#333333" inner="#b3b3b3ff" inner_sel="#5680c2ff" item="#191919ff" @@ -78,7 +103,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="0" - shadedown="0"> + shadedown="0" + roundness="0.5"> </ThemeWidgetColors> </wcol_toggle> <wcol_num> @@ -90,7 +116,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="-10" - shadedown="0"> + shadedown="0" + roundness="0.7"> </ThemeWidgetColors> </wcol_num> <wcol_numslider> @@ -102,7 +129,8 @@ text_sel="#ffffff" show_shaded="TRUE" shadetop="-4" - shadedown="0"> + shadedown="0" + roundness="0.7"> </ThemeWidgetColors> </wcol_numslider> <wcol_box> @@ -114,7 +142,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="0" - shadedown="0"> + shadedown="0" + roundness="0.4"> </ThemeWidgetColors> </wcol_box> <wcol_menu> @@ -126,19 +155,21 @@ text_sel="#cccccc" show_shaded="FALSE" shadetop="10" - shadedown="-10"> + shadedown="-10" + roundness="0.4"> </ThemeWidgetColors> </wcol_menu> <wcol_pulldown> <ThemeWidgetColors outline="#000000" - inner="#3f3f3fff" + inner="#e6e6e699" inner_sel="#5680c2ff" item="#ffffffff" text="#000000" text_sel="#ffffff" show_shaded="FALSE" shadetop="25" - shadedown="-20"> + shadedown="-20" + roundness="0.3"> </ThemeWidgetColors> </wcol_pulldown> <wcol_menu_back> @@ -150,7 +181,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="25" - shadedown="-20"> + shadedown="-20" + roundness="0.5"> </ThemeWidgetColors> </wcol_menu_back> <wcol_pie_menu> @@ -162,7 +194,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="10" - shadedown="-10"> + shadedown="-10" + roundness="1"> </ThemeWidgetColors> </wcol_pie_menu> <wcol_tooltip> @@ -174,7 +207,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="25" - shadedown="-20"> + shadedown="-20" + roundness="0.5"> </ThemeWidgetColors> </wcol_tooltip> <wcol_menu_item> @@ -186,7 +220,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="38" - shadedown="0"> + shadedown="0" + roundness="0.5"> </ThemeWidgetColors> </wcol_menu_item> <wcol_scroll> @@ -198,7 +233,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="5" - shadedown="-5"> + shadedown="-5" + roundness="1"> </ThemeWidgetColors> </wcol_scroll> <wcol_progress> @@ -210,7 +246,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="0" - shadedown="0"> + shadedown="0" + roundness="0.5"> </ThemeWidgetColors> </wcol_progress> <wcol_list_item> @@ -222,7 +259,8 @@ text_sel="#ffffff" show_shaded="FALSE" shadetop="0" - shadedown="0"> + shadedown="0" + roundness="0.4"> </ThemeWidgetColors> </wcol_list_item> <wcol_state> @@ -232,9 +270,24 @@ inner_key_sel="#d7d34b" inner_driven="#b400ff" inner_driven_sel="#9900e6" + inner_overridden="#6bf3cc" + inner_overridden_sel="#5fd9b6" blend="0.5"> </ThemeWidgetStateColors> </wcol_state> + <wcol_tab> + <ThemeWidgetColors outline="#808080" + inner="#8e8e8eff" + inner_sel="#b3b3b3ff" + item="#28292dff" + text="#1a1a1a" + text_sel="#000000" + show_shaded="FALSE" + shadetop="0" + shadedown="0" + roundness="0.3"> + </ThemeWidgetColors> + </wcol_tab> </ThemeUserInterface> </user_interface> <view_3d> @@ -248,13 +301,11 @@ text_grease_pencil="#b5e61d" object_selected="#f15800" object_active="#ffaa40" - object_grouped="#004200" - object_grouped_active="#55bb55" text_keyframe="#ddd700" - camera="#000000" - empty="#000000" - lamp="#00000028" - speaker="#000000" + camera="#b3b3b3" + empty="#b3b3b3" + light="#cccccc33" + speaker="#b3b3b3" vertex="#000000" vertex_select="#ff8500" vertex_size="3" @@ -310,10 +361,10 @@ <ThemeSpaceGradient title="#000000" text="#000000" text_hi="#ffffff" - header="#999999" + header="#99999900" header_text="#000000" header_text_hi="#ffffff" - button="#999999e6" + button="#99999900" button_title="#1a1a1a" button_text="#000000" button_text_hi="#ffffff" @@ -329,7 +380,7 @@ </gradients> <panelcolors> <ThemePanelColors header="#c2c2c2ea" - back="#99999980" + back="#999999cc" show_header="TRUE" show_back="TRUE"> </ThemePanelColors> @@ -371,7 +422,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#adadad" + header="#adadadff" header_text="#000000" header_text_hi="#ffffff" button="#999999e6" @@ -407,7 +458,7 @@ title="#000000" text="#eeeeee" text_hi="#ffffff" - header="#adadad" + header="#adadadff" header_text="#000000" header_text_hi="#ffffff" button="#999999e6" @@ -452,7 +503,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#adadad" + header="#adadadff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -482,8 +533,8 @@ </ThemeNLAEditor> </nla_editor> <dopesheet_editor> - <ThemeDopeSheet grid="#5e5e5e" - frame_current="#60c040" + <ThemeDopeSheet grid="#4d4d4d" + frame_current="#62b347" value_sliders="#000000" view_sliders="#969696" dopesheet_channel="#2e6399" @@ -511,7 +562,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#adadad" + header="#adadadff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -587,7 +638,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#000000" header_text_hi="#ffffff" button="#999999b3" @@ -635,7 +686,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#000000" header_text_hi="#ffffff" button="#959595e6" @@ -664,7 +715,7 @@ title="#181818" text="#000000" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -703,7 +754,7 @@ title="#000000" text="#e6e6e6" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -725,38 +776,6 @@ </space> </ThemeTextEditor> </text_editor> - <timeline> - <ThemeTimeline grid="#5b5b5b" - frame_current="#60c040" - time_keyframe="#ddd700" - time_grease_pencil="#b5e61d"> - <space> - <ThemeSpaceGeneric back="#727272" - title="#000000" - text="#000000" - text_hi="#ffffff" - header="#a6a6a6" - header_text="#0b0b0b" - header_text_hi="#ffffff" - button="#7272727f" - button_title="#000000" - button_text="#000000" - button_text_hi="#ffffff" - tab_active="#6697e6" - tab_inactive="#535353" - tab_back="#404040ff" - tab_outline="#3c3c3c"> - <panelcolors> - <ThemePanelColors header="#c2c2c2ea" - back="#99999980" - show_header="TRUE" - show_back="TRUE"> - </ThemePanelColors> - </panelcolors> - </ThemeSpaceGeneric> - </space> - </ThemeTimeline> - </timeline> <node_editor> <ThemeNodeEditor gp_vertex="#000000" gp_vertex_select="#ff8500" @@ -790,7 +809,7 @@ title="#000000" text="#0d0d0d" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -819,44 +838,15 @@ </space_list> </ThemeNodeEditor> </node_editor> - <logic_editor> - <ThemeLogicEditor> - <space> - <ThemeSpaceGeneric back="#646464" - title="#000000" - text="#000000" - text_hi="#ffffff" - header="#b3b3b3" - header_text="#000000" - header_text_hi="#ffffff" - button="#7272727f" - button_title="#000000" - button_text="#000000" - button_text_hi="#ffffff" - tab_active="#6697e6" - tab_inactive="#535353" - tab_back="#404040ff" - tab_outline="#3c3c3c"> - <panelcolors> - <ThemePanelColors header="#c2c2c2ea" - back="#99999980" - show_header="TRUE" - show_back="TRUE"> - </ThemePanelColors> - </panelcolors> - </ThemeSpaceGeneric> - </space> - </ThemeLogicEditor> - </logic_editor> <outliner> <ThemeOutliner match="#337f33" selected_highlight="#7297d0"> <space> - <ThemeSpaceGeneric back="#b3b3b3" + <ThemeSpaceGeneric back="#999999" title="#000000" - text="#1a1a1a" + text="#000000" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -894,7 +884,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#1a1a1a" header_text_hi="#ffffff" button="#7272727f" @@ -923,7 +913,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#b3b3b3" + header="#b3b3b3ff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -957,7 +947,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#727272" + header="#727272ff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -1010,7 +1000,7 @@ title="#000000" text="#000000" text_hi="#ffffff" - header="#727272" + header="#727272ff" header_text="#000000" header_text_hi="#ffffff" button="#7272727f" @@ -1039,6 +1029,64 @@ </space_list> </ThemeClipEditor> </clip_editor> + <topbar> + <ThemeTopBar> + <space> + <ThemeSpaceGeneric back="#b3b3b3" + title="#ffffff" + text="#ffffff" + text_hi="#ffffff" + header="#808080ff" + header_text="#eeeeee" + header_text_hi="#ffffff" + button="#2f303599" + button_title="#ffffff" + button_text="#ffffff" + button_text_hi="#ffffff" + tab_active="#446499" + tab_inactive="#28292d" + tab_back="#28292dff" + tab_outline="#28292d"> + <panelcolors> + <ThemePanelColors header="#29282eff" + back="#3e3f46ff" + show_header="TRUE" + show_back="TRUE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeTopBar> + </topbar> + <statusbar> + <ThemeStatusBar> + <space> + <ThemeSpaceGeneric back="#393939" + title="#ffffff" + text="#ffffff" + text_hi="#ffffff" + header="#adadadff" + header_text="#1a1a1a" + header_text_hi="#ffffff" + button="#2f303500" + button_title="#ffffff" + button_text="#ffffff" + button_text_hi="#ffffff" + tab_active="#446499" + tab_inactive="#28292d" + tab_back="#28292dff" + tab_outline="#28292d"> + <panelcolors> + <ThemePanelColors header="#29282eff" + back="#3e3f46ff" + show_header="TRUE" + show_back="TRUE"> + </ThemePanelColors> + </panelcolors> + </ThemeSpaceGeneric> + </space> + </ThemeStatusBar> + </statusbar> <bone_color_sets> <ThemeBoneColorSet normal="#9a0000" select="#bd1111" diff --git a/release/scripts/presets/interface_theme/graph.xml b/release/scripts/presets/interface_theme/graph.xml index a032d8bd3b2..904fcdf41ec 100644 --- a/release/scripts/presets/interface_theme/graph.xml +++ b/release/scripts/presets/interface_theme/graph.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#00000028" + light="#00000028" speaker="#000000" camera="#8d8c8d" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/hexagon.xml b/release/scripts/presets/interface_theme/hexagon.xml index 4b24abc5fa7..1ca52b76253 100644 --- a/release/scripts/presets/interface_theme/hexagon.xml +++ b/release/scripts/presets/interface_theme/hexagon.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#00000028" + light="#00000028" speaker="#000000" camera="#000000" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/modern_minimalist.xml b/release/scripts/presets/interface_theme/modern_minimalist.xml index 8ba9402ecdb..3b982514f4f 100644 --- a/release/scripts/presets/interface_theme/modern_minimalist.xml +++ b/release/scripts/presets/interface_theme/modern_minimalist.xml @@ -253,7 +253,7 @@ text_keyframe="#ddd700" camera="#8d8c8d" empty="#8d8c8d" - lamp="#8d8c8d40" + light="#8d8c8d40" speaker="#8d8c8d" vertex="#bfbfbf" vertex_select="#00bdff" diff --git a/release/scripts/presets/interface_theme/north.xml b/release/scripts/presets/interface_theme/north.xml index 69cb90a64ce..8ab51261994 100644 --- a/release/scripts/presets/interface_theme/north.xml +++ b/release/scripts/presets/interface_theme/north.xml @@ -253,7 +253,7 @@ text_keyframe="#ddd700" camera="#000000" empty="#000000" - lamp="#00000028" + light="#00000028" speaker="#000000" vertex="#000000" vertex_select="#f2b252" diff --git a/release/scripts/presets/interface_theme/rtheme.xml b/release/scripts/presets/interface_theme/rtheme.xml index 27f33aa2fe5..34d4f6bd0db 100644 --- a/release/scripts/presets/interface_theme/rtheme.xml +++ b/release/scripts/presets/interface_theme/rtheme.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#00000028" + light="#00000028" speaker="#000000" camera="#000000" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/sandyslate.xml b/release/scripts/presets/interface_theme/sandyslate.xml index c5bae419bca..0b4756a40e8 100644 --- a/release/scripts/presets/interface_theme/sandyslate.xml +++ b/release/scripts/presets/interface_theme/sandyslate.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#ff000080" + light="#ff000080" speaker="#979797" camera="#ff0000" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/science_lab.xml b/release/scripts/presets/interface_theme/science_lab.xml index 2fe4cf99e41..e8a32f6ac29 100644 --- a/release/scripts/presets/interface_theme/science_lab.xml +++ b/release/scripts/presets/interface_theme/science_lab.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#dbac00b9" + light="#dbac00b9" speaker="#229cd8" camera="#e28400" view_overlay="#666666" diff --git a/release/scripts/presets/interface_theme/softblend.xml b/release/scripts/presets/interface_theme/softblend.xml index ab0a5994838..ce20f7d4085 100644 --- a/release/scripts/presets/interface_theme/softblend.xml +++ b/release/scripts/presets/interface_theme/softblend.xml @@ -244,7 +244,7 @@ gp_vertex="#000000" gp_vertex_select="#ff8500" gp_vertex_size="3" - lamp="#ffe56666" + light="#ffe56666" speaker="#c2e787" camera="#000000" view_overlay="#000000" diff --git a/release/scripts/presets/interface_theme/true_blue_menu.xml b/release/scripts/presets/interface_theme/true_blue_menu.xml index 2b464ae120e..26e39f3bcdf 100644 --- a/release/scripts/presets/interface_theme/true_blue_menu.xml +++ b/release/scripts/presets/interface_theme/true_blue_menu.xml @@ -253,7 +253,7 @@ text_keyframe="#ddd700" camera="#000000" empty="#a78721" - lamp="#d6df1628" + light="#d6df1628" speaker="#a83f2d" vertex="#657780" vertex_select="#00cccb" diff --git a/release/scripts/presets/keyconfig/3dsmax.py b/release/scripts/presets/keyconfig/3dsmax.py index e8576cfad9b..8bce68a0a30 100644 --- a/release/scripts/presets/keyconfig/3dsmax.py +++ b/release/scripts/presets/keyconfig/3dsmax.py @@ -7,7 +7,7 @@ kc = wm.keyconfigs.new('3dsmax') # Map Window km = kc.keymaps.new('Window', space_type='EMPTY', region_type='WINDOW', modal=False) -kmi = km.keymap_items.new('wm.window_duplicate', 'W', 'PRESS', ctrl=True, alt=True) +kmi = km.keymap_items.new('wm.window_new', 'W', 'PRESS', ctrl=True, alt=True) kmi = km.keymap_items.new('wm.read_homefile', 'N', 'PRESS', ctrl=True) kmi = km.keymap_items.new('wm.save_homefile', 'U', 'PRESS', ctrl=True) kmi = km.keymap_items.new('wm.call_menu', 'O', 'PRESS', shift=True, ctrl=True) @@ -33,9 +33,6 @@ kmi = km.keymap_items.new('wm.call_menu', 'NDOF_BUTTON_MENU', 'PRESS') kmi.properties.name = 'USERPREF_MT_ndof_settings' kmi = km.keymap_items.new('wm.context_set_enum', 'F2', 'PRESS', shift=True) kmi.properties.data_path = 'area.type' -kmi.properties.value = 'LOGIC_EDITOR' -kmi = km.keymap_items.new('wm.context_set_enum', 'F3', 'PRESS', shift=True, ctrl=True) -kmi.properties.data_path = 'area.type' kmi.properties.value = 'NODE_EDITOR' kmi = km.keymap_items.new('wm.context_set_enum', 'F4', 'PRESS', shift=True) kmi.properties.data_path = 'area.type' @@ -293,7 +290,6 @@ kmi = km.keymap_items.new('wm.context_cycle_enum', 'O', 'PRESS', shift=True) kmi.properties.data_path = 'tool_settings.proportional_edit_falloff' kmi = km.keymap_items.new('wm.context_toggle', 'O', 'PRESS') kmi.properties.data_path = 'tool_settings.use_proportional_edit_objects' -kmi = km.keymap_items.new('view3d.game_start', 'P', 'PRESS', shift=True, ctrl=True, alt=True) kmi = km.keymap_items.new('object.select_all', 'A', 'PRESS', ctrl=True) kmi.properties.action = 'INVERT' kmi = km.keymap_items.new('object.select_linked', 'L', 'PRESS', shift=True) @@ -329,7 +325,6 @@ kmi = km.keymap_items.new('object.hide_view_set', 'H', 'PRESS', shift=True) kmi.properties.unselected = True kmi = km.keymap_items.new('object.hide_render_clear', 'H', 'PRESS', ctrl=True, alt=True) kmi = km.keymap_items.new('object.hide_render_set', 'H', 'PRESS', ctrl=True) -kmi = km.keymap_items.new('object.move_to_layer', 'M', 'PRESS') kmi = km.keymap_items.new('object.delete', 'X', 'PRESS') kmi.properties.use_global = False kmi = km.keymap_items.new('object.delete', 'X', 'PRESS', shift=True) @@ -590,11 +585,11 @@ kmi.properties.nr = 9 kmi = km.keymap_items.new('view3d.layers', 'ZERO', 'PRESS', any=True) kmi.properties.nr = 10 kmi = km.keymap_items.new('wm.context_toggle_enum', 'F3', 'PRESS') -kmi.properties.data_path = 'space_data.viewport_shade' +kmi.properties.data_path = 'space_data.shading.type' kmi.properties.value_1 = 'SOLID' kmi.properties.value_2 = 'WIREFRAME' kmi = km.keymap_items.new('wm.context_toggle_enum', 'Z', 'PRESS', alt=True) -kmi.properties.data_path = 'space_data.viewport_shade' +kmi.properties.data_path = 'space_data.shading.type' kmi.properties.value_1 = 'SOLID' kmi.properties.value_2 = 'TEXTURED' kmi = km.keymap_items.new('view3d.select_or_deselect_all', 'SELECTMOUSE', 'CLICK') @@ -726,7 +721,7 @@ kmi.properties.value_1 = 'VERTEX' kmi.properties.value_2 = 'INCREMENT' kmi = km.keymap_items.new('view3d.select_border', 'EVT_TWEAK_L', 'ANY', ctrl=True) kmi = km.keymap_items.new('wm.context_toggle', 'G', 'PRESS') -kmi.properties.data_path = 'space_data.show_floor' +kmi.properties.data_path = 'space_data.overlay.show_floor' # Map Animation Channels km = kc.keymaps.new('Animation Channels', space_type='EMPTY', region_type='WINDOW', modal=False) @@ -1109,7 +1104,7 @@ kmi = km.keymap_items.new('node.group_edit', 'TAB', 'PRESS') kmi.properties.exit = False kmi = km.keymap_items.new('node.group_edit', 'TAB', 'PRESS', shift=True) kmi.properties.exit = True -kmi = km.keymap_items.new('node.read_renderlayers', 'R', 'PRESS', ctrl=True) +kmi = km.keymap_items.new('node.read_viewlayers', 'R', 'PRESS', ctrl=True) kmi = km.keymap_items.new('node.read_fullsamplelayers', 'R', 'PRESS', shift=True) kmi = km.keymap_items.new('node.render_changed', 'Z', 'PRESS') kmi = km.keymap_items.new('node.clipboard_copy', 'C', 'PRESS', ctrl=True) @@ -2282,17 +2277,6 @@ kmi.properties.value_2 = 'CONNECTED' # Map Armature km = kc.keymaps.new('Armature', space_type='EMPTY', region_type='WINDOW', modal=False) -kmi = km.keymap_items.new('sketch.delete', 'X', 'PRESS') -kmi = km.keymap_items.new('sketch.delete', 'DEL', 'PRESS') -kmi = km.keymap_items.new('sketch.finish_stroke', 'RIGHTMOUSE', 'PRESS') -kmi = km.keymap_items.new('sketch.cancel_stroke', 'ESC', 'PRESS') -kmi = km.keymap_items.new('sketch.gesture', 'LEFTMOUSE', 'PRESS', shift=True) -kmi = km.keymap_items.new('sketch.draw_stroke', 'LEFTMOUSE', 'PRESS') -kmi = km.keymap_items.new('sketch.draw_stroke', 'LEFTMOUSE', 'PRESS', ctrl=True) -kmi.properties.snap = True -kmi = km.keymap_items.new('sketch.draw_preview', 'MOUSEMOVE', 'ANY') -kmi = km.keymap_items.new('sketch.draw_preview', 'MOUSEMOVE', 'ANY', ctrl=True) -kmi.properties.snap = True kmi = km.keymap_items.new('armature.hide', 'H', 'PRESS') kmi.properties.unselected = False kmi = km.keymap_items.new('armature.hide', 'H', 'PRESS', shift=True) diff --git a/release/scripts/presets/keyconfig/blender_27x.py b/release/scripts/presets/keyconfig/blender_27x.py new file mode 100644 index 00000000000..c71b7456cff --- /dev/null +++ b/release/scripts/presets/keyconfig/blender_27x.py @@ -0,0 +1,8645 @@ +keyconfig_data = \ +[("Window", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("wm.window_new", {"type": 'W', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("wm.read_homefile", {"type": 'N', "value": 'PRESS', "ctrl": True}, None), + ("wm.save_homefile", {"type": 'U', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'O', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("name", 'INFO_MT_file_open_recent'), + ], + }, + ), + ("wm.open_mainfile", {"type": 'O', "value": 'PRESS', "ctrl": True}, None), + ("wm.open_mainfile", {"type": 'F1', "value": 'PRESS'}, None), + ("wm.link", {"type": 'O', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("wm.append", {"type": 'F1', "value": 'PRESS', "shift": True}, None), + ("wm.save_mainfile", {"type": 'S', "value": 'PRESS', "ctrl": True}, None), + ("wm.save_mainfile", {"type": 'W', "value": 'PRESS', "ctrl": True}, None), + ("wm.save_as_mainfile", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("wm.save_as_mainfile", {"type": 'F2', "value": 'PRESS'}, None), + ("wm.save_as_mainfile", + {"type": 'S', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("copy", True), + ], + }, + ), + ("wm.window_fullscreen_toggle", {"type": 'F11', "value": 'PRESS', "alt": True}, None), + ("wm.quit_blender", {"type": 'Q', "value": 'PRESS', "ctrl": True}, None), + ("wm.doc_view_manual_ui_context", {"type": 'F1', "value": 'PRESS', "alt": True}, None), + ("wm.redraw_timer", {"type": 'T', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("wm.debug_menu", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("wm.call_menu", + {"type": 'NDOF_BUTTON_MENU', "value": 'PRESS'}, + {"properties": + [("name", 'USERPREF_MT_ndof_settings'), + ], + }, + ), + ("wm.search_menu", {"type": 'SPACE', "value": 'PRESS'}, None), + ("wm.context_set_enum", + {"type": 'F3', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'NODE_EDITOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F4', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'CONSOLE'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F5', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'VIEW_3D'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F6', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'GRAPH_EDITOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F7', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'PROPERTIES'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F8', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'SEQUENCE_EDITOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F9', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'OUTLINER'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F10', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'IMAGE_EDITOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F11', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'TEXT_EDITOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'F12', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'area.type'), + ("value", 'DOPESHEET_EDITOR'), + ], + }, + ), + ("wm.context_scale_float", + {"type": 'NDOF_BUTTON_PLUS', "value": 'PRESS'}, + {"properties": + [("data_path", 'user_preferences.inputs.ndof_sensitivity'), + ("value", 1.1), + ], + }, + ), + ("wm.context_scale_float", + {"type": 'NDOF_BUTTON_MINUS', "value": 'PRESS'}, + {"properties": + [("data_path", 'user_preferences.inputs.ndof_sensitivity'), + ("value", 1.0), + ], + }, + ), + ("wm.context_scale_float", + {"type": 'NDOF_BUTTON_PLUS', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'user_preferences.inputs.ndof_sensitivity'), + ("value", 1.5), + ], + }, + ), + ("wm.context_scale_float", + {"type": 'NDOF_BUTTON_MINUS', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'user_preferences.inputs.ndof_sensitivity'), + ("value", 0.6666667), + ], + }, + ), + ("info.reports_display_update", {"type": 'TIMER_REPORT', "value": 'ANY', "any": True}, None), + ], + }, + ), + ("Screen", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("screen.animation_step", {"type": 'TIMER0', "value": 'ANY', "any": True}, None), + ("screen.region_blend", {"type": 'TIMERREGION', "value": 'ANY', "any": True}, None), + ("screen.screen_set", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("delta", 1), + ], + }, + ), + ("screen.screen_set", + {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("delta", -1), + ], + }, + ), + ("screen.screen_full_area", {"type": 'SPACE', "value": 'PRESS', "shift": True}, None), + ("screen.screen_full_area", + {"type": 'SPACE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("use_hide_panels", True), + ], + }, + ), + ("screen.screenshot", {"type": 'F3', "value": 'PRESS', "ctrl": True}, None), + ("screen.screencast", {"type": 'F3', "value": 'PRESS', "alt": True}, None), + ("screen.space_context_cycle", + {"type": 'TAB', "value": 'PRESS', "ctrl": True}, + {"properties": + [("direction", 'NEXT'), + ], + }, + ), + ("screen.space_context_cycle", + {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("direction", 'PREV'), + ], + }, + ), + ("screen.region_quadview", {"type": 'Q', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("screen.repeat_history", {"type": 'F3', "value": 'PRESS'}, None), + ("screen.repeat_last", {"type": 'R', "value": 'PRESS', "shift": True}, None), + ("screen.region_flip", {"type": 'F5', "value": 'PRESS'}, None), + ("screen.redo_last", {"type": 'F6', "value": 'PRESS'}, None), + ("script.reload", {"type": 'F8', "value": 'PRESS'}, None), + ("file.execute", {"type": 'RET', "value": 'PRESS'}, None), + ("file.execute", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None), + ("file.cancel", {"type": 'ESC', "value": 'PRESS'}, None), + ("ed.undo", {"type": 'Z', "value": 'PRESS', "ctrl": True}, None), + ("ed.redo", {"type": 'Z', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("ed.undo_history", {"type": 'Z', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("render.render", + {"type": 'F12', "value": 'PRESS'}, + {"properties": + [("use_viewport", True), + ], + }, + ), + ("render.render", + {"type": 'F12', "value": 'PRESS', "ctrl": True}, + {"properties": + [("animation", True), + ("use_viewport", True), + ], + }, + ), + ("render.view_cancel", {"type": 'ESC', "value": 'PRESS'}, None), + ("render.view_show", {"type": 'F11', "value": 'PRESS'}, None), + ("render.play_rendered_anim", {"type": 'F11', "value": 'PRESS', "ctrl": True}, None), + ("screen.userpref_show", {"type": 'U', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ], + }, + ), + ("User Interface", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("ui.eyedropper_color", {"type": 'E', "value": 'PRESS'}, None), + ("ui.eyedropper_colorband", {"type": 'E', "value": 'PRESS'}, None), + ("ui.eyedropper_colorband_point", {"type": 'E', "value": 'PRESS', "alt": True}, None), + ("ui.eyedropper_id", {"type": 'E', "value": 'PRESS'}, None), + ("ui.eyedropper_depth", {"type": 'E', "value": 'PRESS'}, None), + ("ui.copy_data_path_button", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("ui.copy_data_path_button", + {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("full_path", True), + ], + }, + ), + ("anim.keyframe_insert_button", {"type": 'I', "value": 'PRESS'}, None), + ("anim.keyframe_delete_button", {"type": 'I', "value": 'PRESS', "alt": True}, None), + ("anim.keyframe_clear_button", {"type": 'I', "value": 'PRESS', "shift": True, "alt": True}, None), + ("anim.driver_button_add", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), + ("anim.driver_button_remove", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("anim.keyingset_button_add", {"type": 'K', "value": 'PRESS'}, None), + ("anim.keyingset_button_remove", {"type": 'K', "value": 'PRESS', "alt": True}, None), + ], + }, + ), + ("View2D", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("view2d.scroller_activate", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("view2d.scroller_activate", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("view2d.pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("view2d.pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None), + ("view2d.pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None), + ("view2d.scroll_right", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("view2d.scroll_left", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("view2d.scroll_down", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None), + ("view2d.scroll_up", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None), + ("view2d.ndof", {"type": 'NDOF_MOTION', "value": 'ANY'}, None), + ("view2d.zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS'}, None), + ("view2d.zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS'}, None), + ("view2d.zoom_out", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None), + ("view2d.zoom_in", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None), + ("view2d.zoom", {"type": 'TRACKPADPAN', "value": 'ANY', "ctrl": True}, None), + ("view2d.smoothview", {"type": 'TIMER1', "value": 'ANY', "any": True}, None), + ("view2d.scroll_down", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None), + ("view2d.scroll_up", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None), + ("view2d.scroll_right", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None), + ("view2d.scroll_left", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None), + ("view2d.zoom", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("view2d.zoom", {"type": 'TRACKPADZOOM', "value": 'ANY'}, None), + ("view2d.zoom_border", {"type": 'B', "value": 'PRESS', "shift": True}, None), + ], + }, + ), + ("Header", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("screen.header_toolbox", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None), + ], + }, + ), + ("View2D Buttons List", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("view2d.scroller_activate", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("view2d.scroller_activate", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("view2d.pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("view2d.pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None), + ("view2d.scroll_down", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, None), + ("view2d.scroll_up", {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, None), + ("view2d.scroll_down", + {"type": 'PAGE_DOWN', "value": 'PRESS'}, + {"properties": + [("page", True), + ], + }, + ), + ("view2d.scroll_up", + {"type": 'PAGE_UP', "value": 'PRESS'}, + {"properties": + [("page", True), + ], + }, + ), + ("view2d.zoom", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("view2d.zoom", {"type": 'TRACKPADZOOM', "value": 'ANY'}, None), + ("view2d.zoom", {"type": 'TRACKPADPAN', "value": 'ANY', "ctrl": True}, None), + ("view2d.zoom_out", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None), + ("view2d.zoom_in", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None), + ("view2d.reset", {"type": 'HOME', "value": 'PRESS'}, None), + ], + }, + ), + ("Frames", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("screen.frame_offset", + {"type": 'UP_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("delta", 10), + ], + }, + ), + ("screen.frame_offset", + {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("delta", -10), + ], + }, + ), + ("screen.frame_offset", + {"type": 'LEFT_ARROW', "value": 'PRESS'}, + {"properties": + [("delta", -1), + ], + }, + ), + ("screen.frame_offset", + {"type": 'RIGHT_ARROW', "value": 'PRESS'}, + {"properties": + [("delta", 1), + ], + }, + ), + ("screen.frame_offset", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("delta", 1), + ], + }, + ), + ("screen.frame_offset", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("delta", -1), + ], + }, + ), + ("screen.frame_jump", + {"type": 'UP_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("end", True), + ], + }, + ), + ("screen.frame_jump", + {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("end", False), + ], + }, + ), + ("screen.frame_jump", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("end", True), + ], + }, + ), + ("screen.frame_jump", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("end", False), + ], + }, + ), + ("screen.keyframe_jump", + {"type": 'UP_ARROW', "value": 'PRESS'}, + {"properties": + [("next", True), + ], + }, + ), + ("screen.keyframe_jump", + {"type": 'DOWN_ARROW', "value": 'PRESS'}, + {"properties": + [("next", False), + ], + }, + ), + ("screen.keyframe_jump", + {"type": 'MEDIA_LAST', "value": 'PRESS'}, + {"properties": + [("next", True), + ], + }, + ), + ("screen.keyframe_jump", + {"type": 'MEDIA_FIRST', "value": 'PRESS'}, + {"properties": + [("next", False), + ], + }, + ), + ("screen.animation_play", {"type": 'A', "value": 'PRESS', "alt": True}, None), + ("screen.animation_play", + {"type": 'A', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("reverse", True), + ], + }, + ), + ("screen.animation_cancel", {"type": 'ESC', "value": 'PRESS'}, None), + ("screen.animation_play", {"type": 'MEDIA_PLAY', "value": 'PRESS'}, None), + ("screen.animation_cancel", {"type": 'MEDIA_STOP', "value": 'PRESS'}, None), + ], + }, + ), + ("Property Editor", + {"space_type": 'PROPERTIES', "region_type": 'WINDOW'}, + {"items": + [("buttons.toolbox", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None), + ], + }, + ), + ("Info", + {"space_type": 'INFO', "region_type": 'WINDOW'}, + {"items": + [("info.select_pick", {"type": 'SELECTMOUSE', "value": 'PRESS'}, None), + ("info.select_all_toggle", {"type": 'A', "value": 'PRESS'}, None), + ("info.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("info.report_replay", {"type": 'R', "value": 'PRESS'}, None), + ("info.report_delete", {"type": 'X', "value": 'PRESS'}, None), + ("info.report_delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("info.report_copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Outliner", + {"space_type": 'OUTLINER', "region_type": 'WINDOW'}, + {"items": + [("outliner.highlight_update", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None), + ("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), + ("outliner.item_activate", + {"type": 'LEFTMOUSE', "value": 'CLICK'}, + {"properties": + [("extend", False), + ("recursive", False), + ], + }, + ), + ("outliner.item_activate", + {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True}, + {"properties": + [("extend", True), + ("recursive", False), + ], + }, + ), + ("outliner.item_activate", + {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True}, + {"properties": + [("extend", False), + ("recursive", True), + ], + }, + ), + ("outliner.item_activate", + {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ("recursive", True), + ], + }, + ), + ("outliner.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("outliner.item_openclose", + {"type": 'RET', "value": 'PRESS'}, + {"properties": + [("all", False), + ], + }, + ), + ("outliner.item_openclose", + {"type": 'RET', "value": 'PRESS', "shift": True}, + {"properties": + [("all", True), + ], + }, + ), + ("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("outliner.operation", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None), + ("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None), + ("outliner.show_hierarchy", {"type": 'HOME', "value": 'PRESS'}, None), + ("outliner.show_active", {"type": 'PERIOD', "value": 'PRESS'}, None), + ("outliner.show_active", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("outliner.scroll_page", + {"type": 'PAGE_DOWN', "value": 'PRESS'}, + {"properties": + [("up", False), + ], + }, + ), + ("outliner.scroll_page", + {"type": 'PAGE_UP', "value": 'PRESS'}, + {"properties": + [("up", True), + ], + }, + ), + ("outliner.show_one_level", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None), + ("outliner.show_one_level", + {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, + {"properties": + [("open", False), + ], + }, + ), + ("outliner.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("outliner.expanded_toggle", {"type": 'A', "value": 'PRESS', "shift": True}, None), + ("outliner.keyingset_add_selected", {"type": 'K', "value": 'PRESS'}, None), + ("outliner.keyingset_remove_selected", {"type": 'K', "value": 'PRESS', "alt": True}, None), + ("anim.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), + ("anim.keyframe_delete", {"type": 'I', "value": 'PRESS', "alt": True}, None), + ("outliner.drivers_add_selected", {"type": 'D', "value": 'PRESS'}, None), + ("outliner.drivers_delete_selected", {"type": 'D', "value": 'PRESS', "alt": True}, None), + ("outliner.collection_new", {"type": 'C', "value": 'PRESS'}, None), + ("outliner.collection_delete", {"type": 'X', "value": 'PRESS'}, None), + ], + }, + ), + ("3D View Generic", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("view3d.properties", {"type": 'N', "value": 'PRESS'}, None), + ("view3d.toolshelf", {"type": 'T', "value": 'PRESS'}, None), + ], + }, + ), + ("Grease Pencil", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("gpencil.draw", + {"type": 'LEFTMOUSE', "value": 'PRESS', "key_modifier": 'D'}, + {"properties": + [("mode", 'DRAW'), + ("wait_for_input", False), + ], + }, + ), + ("gpencil.draw", + {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True, "key_modifier": 'D'}, + {"properties": + [("mode", 'DRAW_STRAIGHT'), + ("wait_for_input", False), + ], + }, + ), + ("gpencil.draw", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True, "key_modifier": 'D'}, + {"properties": + [("mode", 'DRAW_POLY'), + ("wait_for_input", False), + ], + }, + ), + ("gpencil.draw", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "key_modifier": 'D'}, + {"properties": + [("mode", 'ERASER'), + ("wait_for_input", False), + ], + }, + ), + ("gpencil.draw", + {"type": 'ERASER', "value": 'PRESS'}, + {"properties": + [("mode", 'ERASER'), + ("wait_for_input", False), + ], + }, + ), + ("gpencil.editmode_toggle", {"type": 'TAB', "value": 'PRESS', "key_modifier": 'D'}, None), + ("wm.call_menu_pie", + {"type": 'Q', "value": 'PRESS', "key_modifier": 'D'}, + {"properties": + [("name", 'GPENCIL_MT_pie_tool_palette'), + ], + }, + ), + ("wm.call_menu_pie", + {"type": 'W', "value": 'PRESS', "key_modifier": 'D'}, + {"properties": + [("name", 'GPENCIL_MT_pie_settings_palette'), + ], + }, + ), + ("gpencil.blank_frame_add", {"type": 'B', "value": 'PRESS', "key_modifier": 'D'}, None), + ("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "key_modifier": 'D'}, None), + ], + }, + ), + ("Grease Pencil Stroke Edit Mode", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("gpencil.editmode_toggle", {"type": 'TAB', "value": 'PRESS'}, None), + ("wm.call_menu_pie", + {"type": 'E', "value": 'PRESS', "key_modifier": 'D'}, + {"properties": + [("name", 'GPENCIL_MT_pie_sculpt'), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path_primary", 'user_preferences.edit.grease_pencil_eraser_radius'), + ], + }, + ), + ("gpencil.interpolate", {"type": 'E', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("gpencil.interpolate_sequence", {"type": 'E', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("gpencil.brush_paint", + {"type": 'LEFTMOUSE', "value": 'PRESS', "key_modifier": 'E'}, + {"properties": + [("wait_for_input", False), + ], + }, + ), + ("gpencil.brush_paint", + {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True, "key_modifier": 'E'}, + {"properties": + [("wait_for_input", False), + ], + }, + ), + ("gpencil.brush_paint", + {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "key_modifier": 'E'}, + {"properties": + [("wait_for_input", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.strength'), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.size'), + ], + }, + ), + ("gpencil.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("gpencil.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("gpencil.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ("gpencil.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("gpencil.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("gpencil.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("gpencil.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True, "alt": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("gpencil.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("gpencil.select", {"type": 'SELECTMOUSE', "value": 'PRESS'}, None), + ("gpencil.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ("toggle", True), + ], + }, + ), + ("gpencil.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("entire_strokes", True), + ], + }, + ), + ("gpencil.select_linked", {"type": 'L', "value": 'PRESS'}, None), + ("gpencil.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("gpencil.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("wm.call_menu", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_gpencil_delete'), + ], + }, + ), + ("wm.call_menu", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_gpencil_delete'), + ], + }, + ), + ("gpencil.dissolve", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.dissolve", {"type": 'DEL', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'GPENCIL_MT_gpencil_edit_specials'), + ], + }, + ), + ("gpencil.stroke_join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.stroke_join", + {"type": 'J', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'JOINCOPY'), + ], + }, + ), + ("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'S', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'GPENCIL_MT_snap'), + ], + }, + ), + ("gpencil.convert", {"type": 'C', "value": 'PRESS', "alt": True}, None), + ("gpencil.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("gpencil.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("gpencil.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("gpencil.selection_opacity_toggle", {"type": 'H', "value": 'PRESS', "ctrl": True}, None), + ("gpencil.layer_isolate", {"type": 'NUMPAD_ASTERIX', "value": 'PRESS'}, None), + ("gpencil.move_to_layer", {"type": 'M', "value": 'PRESS'}, None), + ("gpencil.brush_select", + {"type": 'ONE', "value": 'PRESS'}, + {"properties": + [("index", 0), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'TWO', "value": 'PRESS'}, + {"properties": + [("index", 1), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'THREE', "value": 'PRESS'}, + {"properties": + [("index", 2), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'FOUR', "value": 'PRESS'}, + {"properties": + [("index", 3), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'FIVE', "value": 'PRESS'}, + {"properties": + [("index", 4), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'SIX', "value": 'PRESS'}, + {"properties": + [("index", 5), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'SEVEN', "value": 'PRESS'}, + {"properties": + [("index", 6), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'EIGHT', "value": 'PRESS'}, + {"properties": + [("index", 7), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'NINE', "value": 'PRESS'}, + {"properties": + [("index", 8), + ], + }, + ), + ("gpencil.brush_select", + {"type": 'ZERO', "value": 'PRESS'}, + {"properties": + [("index", 9), + ], + }, + ), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("transform.mirror", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ("transform.bend", {"type": 'W', "value": 'PRESS', "shift": True}, None), + ("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None), + ("transform.shear", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("transform.transform", + {"type": 'S', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'GPENCIL_SHRINKFATTEN'), + ], + }, + ), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'ENABLED'), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'CONNECTED'), + ], + }, + ), + ], + }, + ), + ("Face Mask", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("paint.face_select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("paint.face_select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("paint.face_select_hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("paint.face_select_hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("paint.face_select_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("paint.face_select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("paint.face_select_linked_pick", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("deselect", False), + ], + }, + ), + ("paint.face_select_linked_pick", + {"type": 'L', "value": 'PRESS', "shift": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ], + }, + ), + ("Weight Paint Vertex Selection", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("paint.vert_select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("paint.vert_select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("view3d.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("view3d.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("view3d.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("view3d.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ], + }, + ), + ("Pose", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("object.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'INFO_MT_add'), + ], + }, + ), + ("pose.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("pose.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("pose.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_pose_apply'), + ], + }, + ), + ("pose.rot_clear", {"type": 'R', "value": 'PRESS', "alt": True}, None), + ("pose.loc_clear", {"type": 'G', "value": 'PRESS', "alt": True}, None), + ("pose.scale_clear", {"type": 'S', "value": 'PRESS', "alt": True}, None), + ("pose.quaternions_flip", {"type": 'F', "value": 'PRESS', "alt": True}, None), + ("pose.rotation_mode_set", {"type": 'R', "value": 'PRESS', "ctrl": True}, None), + ("pose.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("pose.paste", + {"type": 'V', "value": 'PRESS', "ctrl": True}, + {"properties": + [("flipped", False), + ], + }, + ), + ("pose.paste", + {"type": 'V', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("flipped", True), + ], + }, + ), + ("pose.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("pose.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("pose.select_parent", {"type": 'P', "value": 'PRESS', "shift": True}, None), + ("pose.select_hierarchy", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("direction", 'PARENT'), + ("extend", False), + ], + }, + ), + ("pose.select_hierarchy", + {"type": 'LEFT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'PARENT'), + ("extend", True), + ], + }, + ), + ("pose.select_hierarchy", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("direction", 'CHILD'), + ("extend", False), + ], + }, + ), + ("pose.select_hierarchy", + {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'CHILD'), + ("extend", True), + ], + }, + ), + ("pose.select_linked", {"type": 'L', "value": 'PRESS'}, None), + ("pose.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("pose.select_mirror", {"type": 'F', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("pose.constraint_add_with_targets", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("pose.constraints_clear", {"type": 'C', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("pose.ik_add", {"type": 'I', "value": 'PRESS', "shift": True}, None), + ("pose.ik_clear", {"type": 'I', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("wm.call_menu", + {"type": 'G', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_pose_group'), + ], + }, + ), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'VIEW3D_MT_bone_options_toggle'), + ], + }, + ), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_bone_options_enable'), + ], + }, + ), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS', "alt": True}, + {"properties": + [("name", 'VIEW3D_MT_bone_options_disable'), + ], + }, + ), + ("armature.layers_show_all", {"type": 'ACCENT_GRAVE', "value": 'PRESS', "ctrl": True}, None), + ("armature.armature_layers", {"type": 'M', "value": 'PRESS', "shift": True}, None), + ("pose.bone_layers", {"type": 'M', "value": 'PRESS'}, None), + ("wm.context_toggle", + {"type": 'Z', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.overlay.show_bone_select'), + ], + }, + ), + ("transform.transform", + {"type": 'S', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("mode", 'BONE_SIZE'), + ], + }, + ), + ("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS'}, None), + ("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None), + ("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("poselib.browse_interactive", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("poselib.pose_add", {"type": 'L', "value": 'PRESS', "shift": True}, None), + ("poselib.pose_remove", {"type": 'L', "value": 'PRESS', "alt": True}, None), + ("poselib.pose_rename", {"type": 'L', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("pose.push", {"type": 'E', "value": 'PRESS', "ctrl": True}, None), + ("pose.relax", {"type": 'E', "value": 'PRESS', "alt": True}, None), + ("pose.breakdown", {"type": 'E', "value": 'PRESS', "shift": True}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_pose_specials'), + ], + }, + ), + ("wm.call_menu", + {"type": 'P', "value": 'PRESS', "alt": True}, + {"properties": + [("name", 'VIEW3D_MT_pose_propagate'), + ], + }, + ), + ], + }, + ), + ("Object Mode", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.use_proportional_edit_objects'), + ], + }, + ), + ("object.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("object.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("object.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("object.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("object.select_linked", {"type": 'L', "value": 'PRESS', "shift": True}, None), + ("object.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("object.select_mirror", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("object.select_hierarchy", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("direction", 'PARENT'), + ("extend", False), + ], + }, + ), + ("object.select_hierarchy", + {"type": 'LEFT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'PARENT'), + ("extend", True), + ], + }, + ), + ("object.select_hierarchy", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("direction", 'CHILD'), + ("extend", False), + ], + }, + ), + ("object.select_hierarchy", + {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'CHILD'), + ("extend", True), + ], + }, + ), + ("object.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("object.parent_no_inverse_set", {"type": 'P', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("object.parent_clear", {"type": 'P', "value": 'PRESS', "alt": True}, None), + ("object.track_set", {"type": 'T', "value": 'PRESS', "ctrl": True}, None), + ("object.track_clear", {"type": 'T', "value": 'PRESS', "alt": True}, None), + ("object.constraint_add_with_targets", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("object.constraints_clear", {"type": 'C', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("object.location_clear", + {"type": 'G', "value": 'PRESS', "alt": True}, + {"properties": + [("clear_delta", False), + ], + }, + ), + ("object.rotation_clear", + {"type": 'R', "value": 'PRESS', "alt": True}, + {"properties": + [("clear_delta", False), + ], + }, + ), + ("object.scale_clear", + {"type": 'S', "value": 'PRESS', "alt": True}, + {"properties": + [("clear_delta", False), + ], + }, + ), + ("object.origin_clear", {"type": 'O', "value": 'PRESS', "alt": True}, None), + ("object.delete", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("use_global", False), + ], + }, + ), + ("object.delete", + {"type": 'X', "value": 'PRESS', "shift": True}, + {"properties": + [("use_global", True), + ], + }, + ), + ("object.delete", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("use_global", False), + ], + }, + ), + ("object.delete", + {"type": 'DEL', "value": 'PRESS', "shift": True}, + {"properties": + [("use_global", True), + ], + }, + ), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'INFO_MT_add'), + ], + }, + ), + ("object.duplicates_make_real", {"type": 'A', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_object_apply'), + ], + }, + ), + ("wm.call_menu", + {"type": 'U', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_make_single_user'), + ], + }, + ), + ("wm.call_menu", + {"type": 'L', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_make_links'), + ], + }, + ), + ("object.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("object.duplicate_move_linked", {"type": 'D', "value": 'PRESS', "alt": True}, None), + ("object.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None), + ("object.convert", {"type": 'C', "value": 'PRESS', "alt": True}, None), + ("object.proxy_make", {"type": 'P', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("object.make_local", {"type": 'L', "value": 'PRESS'}, None), + ("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS'}, None), + ("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True}, None), + ("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("collection.create", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), + ("collection.objects_remove", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("collection.objects_remove_all", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("collection.objects_add_active", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("collection.objects_remove_active", {"type": 'G', "value": 'PRESS', "shift": True, "alt": True}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_object_specials'), + ], + }, + ), + ("object.data_transfer", {"type": 'T', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("object.subdivision_set", + {"type": 'ZERO', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 0), + ], + }, + ), + ("object.subdivision_set", + {"type": 'ONE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 1), + ], + }, + ), + ("object.subdivision_set", + {"type": 'TWO', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 2), + ], + }, + ), + ("object.subdivision_set", + {"type": 'THREE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 3), + ], + }, + ), + ("object.subdivision_set", + {"type": 'FOUR', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 4), + ], + }, + ), + ("object.subdivision_set", + {"type": 'FIVE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 5), + ], + }, + ), + ("object.move_to_collection", {"type": 'M', "value": 'PRESS'}, None), + ], + }, + ), + ("Paint Curve", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("paintcurve.add_point_slide", {"type": 'ACTIONMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("paintcurve.select", {"type": 'SELECTMOUSE', "value": 'PRESS'}, None), + ("paintcurve.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("paintcurve.slide", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("paintcurve.slide", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("align", True), + ], + }, + ), + ("paintcurve.select", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("toggle", True), + ], + }, + ), + ("paintcurve.cursor", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("paintcurve.delete_point", {"type": 'X', "value": 'PRESS'}, None), + ("paintcurve.delete_point", {"type": 'DEL', "value": 'PRESS'}, None), + ("paintcurve.draw", {"type": 'RET', "value": 'PRESS'}, None), + ("paintcurve.draw", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ], + }, + ), + ("Curve", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("wm.call_menu", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'INFO_MT_edit_curve_add'), + ], + }, + ), + ("curve.handle_type_set", {"type": 'V', "value": 'PRESS'}, None), + ("curve.vertex_add", {"type": 'ACTIONMOUSE', "value": 'CLICK', "ctrl": True}, None), + ("curve.draw", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("wait_for_input", False), + ], + }, + ), + ("curve.draw", + {"type": 'PEN', "value": 'PRESS', "shift": True}, + {"properties": + [("wait_for_input", False), + ], + }, + ), + ("curve.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("curve.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("curve.select_row", {"type": 'R', "value": 'PRESS', "shift": True}, None), + ("curve.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("curve.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("curve.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("curve.select_similar", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("curve.select_linked_pick", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("deselect", False), + ], + }, + ), + ("curve.select_linked_pick", + {"type": 'L', "value": 'PRESS', "shift": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("curve.shortest_path_pick", {"type": 'SELECTMOUSE', "value": 'CLICK', "ctrl": True}, None), + ("curve.separate", {"type": 'P', "value": 'PRESS'}, None), + ("curve.split", {"type": 'Y', "value": 'PRESS'}, None), + ("curve.extrude_move", {"type": 'E', "value": 'PRESS'}, None), + ("curve.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("curve.make_segment", {"type": 'F', "value": 'PRESS'}, None), + ("curve.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None), + ("wm.call_menu", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_curve_delete'), + ], + }, + ), + ("wm.call_menu", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_curve_delete'), + ], + }, + ), + ("curve.dissolve_verts", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), + ("curve.dissolve_verts", {"type": 'DEL', "value": 'PRESS', "ctrl": True}, None), + ("curve.tilt_clear", {"type": 'T', "value": 'PRESS', "alt": True}, None), + ("transform.tilt", {"type": 'T', "value": 'PRESS', "ctrl": True}, None), + ("transform.transform", + {"type": 'S', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'CURVE_SHRINKFATTEN'), + ], + }, + ), + ("curve.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("curve.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("curve.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("curve.normals_make_consistent", {"type": 'N', "value": 'PRESS', "ctrl": True}, None), + ("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_curve_specials'), + ], + }, + ), + ("wm.call_menu", + {"type": 'H', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_hook'), + ], + }, + ), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'ENABLED'), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'CONNECTED'), + ], + }, + ), + ], + }, + ), + ("Image Paint", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("paint.image_paint", + {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": + [("mode", 'NORMAL'), + ], + }, + ), + ("paint.image_paint", + {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'INVERT'), + ], + }, + ), + ("paint.brush_colors_flip", {"type": 'X', "value": 'PRESS'}, None), + ("paint.grab_clone", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None), + ("paint.sample_color", {"type": 'S', "value": 'PRESS'}, None), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 0), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 1), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 2), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 3), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 4), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 5), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 6), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 7), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 8), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS'}, + {"properties": + [("mode", 'image_paint'), + ("index", 9), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 10), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 11), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 12), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 13), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 14), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 15), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 16), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 17), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 18), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'image_paint'), + ("index", 19), + ], + }, + ), + ("brush.scale_size", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 0.9), + ], + }, + ), + ("brush.scale_size", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 1.1111112), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.image_paint.brush.size'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.size'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_size'), + ("rotation_path", 'tool_settings.image_paint.brush.mask_texture_slot.angle'), + ("color_path", 'tool_settings.image_paint.brush.cursor_color_add'), + ("fill_color_path", 'tool_settings.image_paint.brush.color'), + ("fill_color_override_path", 'tool_settings.unified_paint_settings.color'), + ("fill_color_override_test_path", 'tool_settings.unified_paint_settings.use_unified_color'), + ("zoom_path", 'space_data.zoom'), + ("image_id", 'tool_settings.image_paint.brush'), + ("secondary_tex", True), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path_primary", 'tool_settings.image_paint.brush.strength'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.strength'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_strength'), + ("rotation_path", 'tool_settings.image_paint.brush.mask_texture_slot.angle'), + ("color_path", 'tool_settings.image_paint.brush.cursor_color_add'), + ("fill_color_path", 'tool_settings.image_paint.brush.color'), + ("fill_color_override_path", 'tool_settings.unified_paint_settings.color'), + ("fill_color_override_test_path", 'tool_settings.unified_paint_settings.use_unified_color'), + ("zoom_path", ''), + ("image_id", 'tool_settings.image_paint.brush'), + ("secondary_tex", True), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path_primary", 'tool_settings.image_paint.brush.texture_slot.angle'), + ("data_path_secondary", ''), + ("use_secondary", ''), + ("rotation_path", 'tool_settings.image_paint.brush.texture_slot.angle'), + ("color_path", 'tool_settings.image_paint.brush.cursor_color_add'), + ("fill_color_path", 'tool_settings.image_paint.brush.color'), + ("fill_color_override_path", 'tool_settings.unified_paint_settings.color'), + ("fill_color_override_test_path", 'tool_settings.unified_paint_settings.use_unified_color'), + ("zoom_path", ''), + ("image_id", 'tool_settings.image_paint.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("data_path_primary", 'tool_settings.image_paint.brush.mask_texture_slot.angle'), + ("data_path_secondary", ''), + ("use_secondary", ''), + ("rotation_path", 'tool_settings.image_paint.brush.mask_texture_slot.angle'), + ("color_path", 'tool_settings.image_paint.brush.cursor_color_add'), + ("fill_color_path", 'tool_settings.image_paint.brush.color'), + ("fill_color_override_path", 'tool_settings.unified_paint_settings.color'), + ("fill_color_override_test_path", 'tool_settings.unified_paint_settings.use_unified_color'), + ("zoom_path", ''), + ("image_id", 'tool_settings.image_paint.brush'), + ("secondary_tex", True), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS'}, + {"properties": + [("mode", 'TRANSLATION'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'SCALE'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'ROTATION'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'TRANSLATION'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("mode", 'SCALE'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("mode", 'ROTATION'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'M', "value": 'PRESS'}, + {"properties": + [("data_path", 'image_paint_object.data.use_paint_mask'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'S', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.image_paint.brush.use_smooth_stroke'), + ], + }, + ), + ("wm.call_menu", + {"type": 'R', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_angle_control'), + ], + }, + ), + ("wm.context_menu_enum", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.image_paint.brush.stroke_method'), + ], + }, + ), + ], + }, + ), + ("Vertex Paint", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("paint.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("paint.brush_colors_flip", {"type": 'X', "value": 'PRESS'}, None), + ("paint.sample_color", {"type": 'S', "value": 'PRESS'}, None), + ("paint.vertex_color_set", {"type": 'K', "value": 'PRESS', "shift": True}, None), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 0), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 1), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 2), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 3), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 4), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 5), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 6), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 7), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 8), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS'}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 9), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 10), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 11), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 12), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 13), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 14), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 15), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 16), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 17), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 18), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'vertex_paint'), + ("index", 19), + ], + }, + ), + ("brush.scale_size", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 0.9), + ], + }, + ), + ("brush.scale_size", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 1.1111112), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.vertex_paint.brush.size'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.size'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_size'), + ("rotation_path", 'tool_settings.vertex_paint.brush.texture_slot.angle'), + ("color_path", 'tool_settings.vertex_paint.brush.cursor_color_add'), + ("fill_color_path", 'tool_settings.vertex_paint.brush.color'), + ("fill_color_override_path", 'tool_settings.unified_paint_settings.color'), + ("fill_color_override_test_path", 'tool_settings.unified_paint_settings.use_unified_color'), + ("zoom_path", ''), + ("image_id", 'tool_settings.vertex_paint.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path_primary", 'tool_settings.vertex_paint.brush.strength'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.strength'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_strength'), + ("rotation_path", 'tool_settings.vertex_paint.brush.texture_slot.angle'), + ("color_path", 'tool_settings.vertex_paint.brush.cursor_color_add'), + ("fill_color_path", 'tool_settings.vertex_paint.brush.color'), + ("fill_color_override_path", 'tool_settings.unified_paint_settings.color'), + ("fill_color_override_test_path", 'tool_settings.unified_paint_settings.use_unified_color'), + ("zoom_path", ''), + ("image_id", 'tool_settings.vertex_paint.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path_primary", 'tool_settings.vertex_paint.brush.texture_slot.angle'), + ("data_path_secondary", ''), + ("use_secondary", ''), + ("rotation_path", 'tool_settings.vertex_paint.brush.texture_slot.angle'), + ("color_path", 'tool_settings.vertex_paint.brush.cursor_color_add'), + ("fill_color_path", 'tool_settings.vertex_paint.brush.color'), + ("fill_color_override_path", 'tool_settings.unified_paint_settings.color'), + ("fill_color_override_test_path", 'tool_settings.unified_paint_settings.use_unified_color'), + ("zoom_path", ''), + ("image_id", 'tool_settings.vertex_paint.brush'), + ("secondary_tex", False), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS'}, + {"properties": + [("mode", 'TRANSLATION'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'SCALE'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'ROTATION'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'TRANSLATION'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("mode", 'SCALE'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("mode", 'ROTATION'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'M', "value": 'PRESS'}, + {"properties": + [("data_path", 'vertex_paint_object.data.use_paint_mask'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'S', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.vertex_paint.brush.use_smooth_stroke'), + ], + }, + ), + ("wm.call_menu", + {"type": 'R', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_angle_control'), + ], + }, + ), + ("wm.context_menu_enum", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.vertex_paint.brush.stroke_method'), + ], + }, + ), + ], + }, + ), + ("Weight Paint", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("paint.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("paint.weight_sample", {"type": 'ACTIONMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("paint.weight_sample_group", {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True}, None), + ("paint.weight_gradient", + {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("type", 'LINEAR'), + ], + }, + ), + ("paint.weight_gradient", + {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("type", 'RADIAL'), + ], + }, + ), + ("paint.weight_set", {"type": 'K', "value": 'PRESS', "shift": True}, None), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 0), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 1), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 2), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 3), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 4), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 5), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 6), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 7), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 8), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS'}, + {"properties": + [("mode", 'weight_paint'), + ("index", 9), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 10), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 11), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 12), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 13), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 14), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 15), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 16), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 17), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 18), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'weight_paint'), + ("index", 19), + ], + }, + ), + ("brush.scale_size", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 0.9), + ], + }, + ), + ("brush.scale_size", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 1.1111112), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.weight_paint.brush.size'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.size'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_size'), + ("rotation_path", 'tool_settings.weight_paint.brush.texture_slot.angle'), + ("color_path", 'tool_settings.weight_paint.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.weight_paint.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path_primary", 'tool_settings.weight_paint.brush.strength'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.strength'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_strength'), + ("rotation_path", 'tool_settings.weight_paint.brush.texture_slot.angle'), + ("color_path", 'tool_settings.weight_paint.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.weight_paint.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.weight_paint.brush.weight'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.weight'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_weight'), + ("rotation_path", 'tool_settings.weight_paint.brush.texture_slot.angle'), + ("color_path", 'tool_settings.weight_paint.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.weight_paint.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.context_menu_enum", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.vertex_paint.brush.stroke_method'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'M', "value": 'PRESS'}, + {"properties": + [("data_path", 'weight_paint_object.data.use_paint_mask'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'V', "value": 'PRESS'}, + {"properties": + [("data_path", 'weight_paint_object.data.use_paint_mask_vertex'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'S', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.weight_paint.brush.use_smooth_stroke'), + ], + }, + ), + ], + }, + ), + ("Sculpt", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("sculpt.brush_stroke", + {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": + [("mode", 'NORMAL'), + ], + }, + ), + ("sculpt.brush_stroke", + {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'INVERT'), + ], + }, + ), + ("sculpt.brush_stroke", + {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'SMOOTH'), + ], + }, + ), + ("paint.hide_show", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("action", 'SHOW'), + ("area", 'INSIDE'), + ], + }, + ), + ("paint.hide_show", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("action", 'HIDE'), + ("area", 'INSIDE'), + ], + }, + ), + ("paint.hide_show", + {"type": 'H', "value": 'PRESS', "alt": True}, + {"properties": + [("action", 'SHOW'), + ("area", 'ALL'), + ], + }, + ), + ("object.subdivision_set", + {"type": 'ZERO', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 0), + ], + }, + ), + ("object.subdivision_set", + {"type": 'ONE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 1), + ], + }, + ), + ("object.subdivision_set", + {"type": 'TWO', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 2), + ], + }, + ), + ("object.subdivision_set", + {"type": 'THREE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 3), + ], + }, + ), + ("object.subdivision_set", + {"type": 'FOUR', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 4), + ], + }, + ), + ("object.subdivision_set", + {"type": 'FIVE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 5), + ], + }, + ), + ("paint.mask_flood_fill", + {"type": 'M', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'VALUE'), + ("value", 0.0), + ], + }, + ), + ("paint.mask_flood_fill", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'INVERT'), + ], + }, + ), + ("paint.mask_lasso_gesture", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("wm.context_toggle", + {"type": 'M', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'scene.tool_settings.sculpt.show_mask'), + ], + }, + ), + ("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), + ("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("object.subdivision_set", + {"type": 'PAGE_UP', "value": 'PRESS'}, + {"properties": + [("level", 1), + ("relative", True), + ], + }, + ), + ("object.subdivision_set", + {"type": 'PAGE_DOWN', "value": 'PRESS'}, + {"properties": + [("level", -1), + ("relative", True), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 0), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 1), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 2), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 3), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 4), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 5), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 6), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 7), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 8), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS'}, + {"properties": + [("mode", 'sculpt'), + ("index", 9), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ONE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 10), + ], + }, + ), + ("brush.active_index_set", + {"type": 'TWO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 11), + ], + }, + ), + ("brush.active_index_set", + {"type": 'THREE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 12), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FOUR', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 13), + ], + }, + ), + ("brush.active_index_set", + {"type": 'FIVE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 14), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SIX', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 15), + ], + }, + ), + ("brush.active_index_set", + {"type": 'SEVEN', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 16), + ], + }, + ), + ("brush.active_index_set", + {"type": 'EIGHT', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 17), + ], + }, + ), + ("brush.active_index_set", + {"type": 'NINE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 18), + ], + }, + ), + ("brush.active_index_set", + {"type": 'ZERO', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'sculpt'), + ("index", 19), + ], + }, + ), + ("brush.scale_size", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 0.9), + ], + }, + ), + ("brush.scale_size", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 1.1111112), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.sculpt.brush.size'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.size'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_size'), + ("rotation_path", 'tool_settings.sculpt.brush.texture_slot.angle'), + ("color_path", 'tool_settings.sculpt.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.sculpt.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path_primary", 'tool_settings.sculpt.brush.strength'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.strength'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_strength'), + ("rotation_path", 'tool_settings.sculpt.brush.texture_slot.angle'), + ("color_path", 'tool_settings.sculpt.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.sculpt.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path_primary", 'tool_settings.sculpt.brush.texture_slot.angle'), + ("data_path_secondary", ''), + ("use_secondary", ''), + ("rotation_path", 'tool_settings.sculpt.brush.texture_slot.angle'), + ("color_path", 'tool_settings.sculpt.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.sculpt.brush'), + ("secondary_tex", False), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS'}, + {"properties": + [("mode", 'TRANSLATION'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'SCALE'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'ROTATION'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'TRANSLATION'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("mode", 'SCALE'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("brush.stencil_control", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("mode", 'ROTATION'), + ("texmode", 'SECONDARY'), + ], + }, + ), + ("paint.brush_select", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'DRAW'), + ], + }, + ), + ("paint.brush_select", + {"type": 'S', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'SMOOTH'), + ], + }, + ), + ("paint.brush_select", + {"type": 'P', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'PINCH'), + ], + }, + ), + ("paint.brush_select", + {"type": 'I', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'INFLATE'), + ], + }, + ), + ("paint.brush_select", + {"type": 'G', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'GRAB'), + ], + }, + ), + ("paint.brush_select", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'LAYER'), + ], + }, + ), + ("paint.brush_select", + {"type": 'T', "value": 'PRESS', "shift": True}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'FLATTEN'), + ], + }, + ), + ("paint.brush_select", + {"type": 'C', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'CLAY'), + ], + }, + ), + ("paint.brush_select", + {"type": 'C', "value": 'PRESS', "shift": True}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'CREASE'), + ], + }, + ), + ("paint.brush_select", + {"type": 'K', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'SNAKE_HOOK'), + ], + }, + ), + ("paint.brush_select", + {"type": 'M', "value": 'PRESS'}, + {"properties": + [("paint_mode", 'SCULPT'), + ("sculpt_tool", 'MASK'), + ("toggle", True), + ("create_missing", True), + ], + }, + ), + ("wm.context_menu_enum", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.sculpt.brush.stroke_method'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'S', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.sculpt.brush.use_smooth_stroke'), + ], + }, + ), + ("wm.call_menu", + {"type": 'R', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_angle_control'), + ], + }, + ), + ], + }, + ), + ("Mesh", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("mesh.loopcut_slide", {"type": 'R', "value": 'PRESS', "ctrl": True}, None), + ("mesh.offset_edge_loops_slide", {"type": 'R', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("mesh.inset", {"type": 'I', "value": 'PRESS'}, None), + ("mesh.poke", {"type": 'P', "value": 'PRESS', "alt": True}, None), + ("mesh.bevel", + {"type": 'B', "value": 'PRESS', "ctrl": True}, + {"properties": + [("vertex_only", False), + ], + }, + ), + ("mesh.bevel", + {"type": 'B', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("vertex_only", True), + ], + }, + ), + ("mesh.loop_select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", False), + ], + }, + ), + ("mesh.loop_select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", True), + ], + }, + ), + ("mesh.edgering_select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", False), + ], + }, + ), + ("mesh.edgering_select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", True), + ], + }, + ), + ("mesh.shortest_path_pick", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("use_fill", False), + ], + }, + ), + ("mesh.shortest_path_pick", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("use_fill", True), + ], + }, + ), + ("mesh.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("mesh.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("mesh.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("mesh.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("mesh.select_next_item", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("mesh.select_prev_item", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("mesh.select_non_manifold", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("mesh.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("mesh.select_linked_pick", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("deselect", False), + ], + }, + ), + ("mesh.select_linked_pick", + {"type": 'L', "value": 'PRESS', "shift": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("mesh.faces_select_linked_flat", {"type": 'F', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("wm.call_menu", + {"type": 'G', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_select_similar'), + ], + }, + ), + ("wm.call_menu", + {"type": 'TAB', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_select_mode'), + ], + }, + ), + ("mesh.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("mesh.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("mesh.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("mesh.normals_make_consistent", + {"type": 'N', "value": 'PRESS', "ctrl": True}, + {"properties": + [("inside", False), + ], + }, + ), + ("mesh.normals_make_consistent", + {"type": 'N', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("inside", True), + ], + }, + ), + ("view3d.edit_mesh_extrude_move_normal", {"type": 'E', "value": 'PRESS'}, None), + ("wm.call_menu", + {"type": 'E', "value": 'PRESS', "alt": True}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_extrude'), + ], + }, + ), + ("transform.edge_crease", {"type": 'E', "value": 'PRESS', "shift": True}, None), + ("mesh.spin", {"type": 'R', "value": 'PRESS', "alt": True}, None), + ("mesh.fill", {"type": 'F', "value": 'PRESS', "alt": True}, None), + ("mesh.beautify_fill", {"type": 'F', "value": 'PRESS', "shift": True, "alt": True}, None), + ("mesh.quads_convert_to_tris", + {"type": 'T', "value": 'PRESS', "ctrl": True}, + {"properties": + [("quad_method", 'BEAUTY'), + ("ngon_method", 'BEAUTY'), + ], + }, + ), + ("mesh.quads_convert_to_tris", + {"type": 'T', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("quad_method", 'FIXED'), + ("ngon_method", 'CLIP'), + ], + }, + ), + ("mesh.tris_convert_to_quads", {"type": 'J', "value": 'PRESS', "alt": True}, None), + ("mesh.rip_move", + {"type": 'V', "value": 'PRESS'}, + {"properties": + [("MESH_OT_rip", + [("use_fill", False), + ], + ), + ], + }, + ), + ("mesh.rip_move", + {"type": 'V', "value": 'PRESS', "alt": True}, + {"properties": + [("MESH_OT_rip", + [("use_fill", True), + ], + ), + ], + }, + ), + ("mesh.rip_edge_move", {"type": 'D', "value": 'PRESS', "alt": True}, None), + ("mesh.merge", {"type": 'M', "value": 'PRESS', "alt": True}, None), + ("transform.shrink_fatten", {"type": 'S', "value": 'PRESS', "alt": True}, None), + ("mesh.edge_face_add", {"type": 'F', "value": 'PRESS'}, None), + ("mesh.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'INFO_MT_mesh_add'), + ], + }, + ), + ("mesh.separate", {"type": 'P', "value": 'PRESS'}, None), + ("mesh.split", {"type": 'Y', "value": 'PRESS'}, None), + ("mesh.vert_connect_path", {"type": 'J', "value": 'PRESS'}, None), + ("transform.vert_slide", {"type": 'V', "value": 'PRESS', "shift": True}, None), + ("mesh.dupli_extrude_cursor", + {"type": 'ACTIONMOUSE', "value": 'CLICK', "ctrl": True}, + {"properties": + [("rotate_source", True), + ], + }, + ), + ("mesh.dupli_extrude_cursor", + {"type": 'ACTIONMOUSE', "value": 'CLICK', "shift": True, "ctrl": True}, + {"properties": + [("rotate_source", False), + ], + }, + ), + ("wm.call_menu", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_delete'), + ], + }, + ), + ("wm.call_menu", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_delete'), + ], + }, + ), + ("mesh.dissolve_mode", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), + ("mesh.dissolve_mode", {"type": 'DEL', "value": 'PRESS', "ctrl": True}, None), + ("mesh.knife_tool", + {"type": 'K', "value": 'PRESS'}, + {"properties": + [("use_occlude_geometry", True), + ("only_selected", False), + ], + }, + ), + ("mesh.knife_tool", + {"type": 'K', "value": 'PRESS', "shift": True}, + {"properties": + [("use_occlude_geometry", False), + ("only_selected", True), + ], + }, + ), + ("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_specials'), + ], + }, + ), + ("wm.call_menu", + {"type": 'F', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_faces'), + ], + }, + ), + ("wm.call_menu", + {"type": 'E', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_edges'), + ], + }, + ), + ("wm.call_menu", + {"type": 'V', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_edit_mesh_vertices'), + ], + }, + ), + ("wm.call_menu", + {"type": 'H', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_hook'), + ], + }, + ), + ("wm.call_menu", + {"type": 'U', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_uv_map'), + ], + }, + ), + ("wm.call_menu", + {"type": 'G', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_vertex_group'), + ], + }, + ), + ("object.subdivision_set", + {"type": 'ZERO', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 0), + ], + }, + ), + ("object.subdivision_set", + {"type": 'ONE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 1), + ], + }, + ), + ("object.subdivision_set", + {"type": 'TWO', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 2), + ], + }, + ), + ("object.subdivision_set", + {"type": 'THREE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 3), + ], + }, + ), + ("object.subdivision_set", + {"type": 'FOUR', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 4), + ], + }, + ), + ("object.subdivision_set", + {"type": 'FIVE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("level", 5), + ], + }, + ), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'ENABLED'), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'CONNECTED'), + ], + }, + ), + ], + }, + ), + ("Armature", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("armature.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("armature.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("armature.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("armature.align", {"type": 'A', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("armature.calculate_roll", {"type": 'N', "value": 'PRESS', "ctrl": True}, None), + ("armature.roll_clear", {"type": 'R', "value": 'PRESS', "alt": True}, None), + ("armature.switch_direction", {"type": 'F', "value": 'PRESS', "alt": True}, None), + ("armature.bone_primitive_add", {"type": 'A', "value": 'PRESS', "shift": True}, None), + ("armature.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("armature.parent_clear", {"type": 'P', "value": 'PRESS', "alt": True}, None), + ("armature.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("armature.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("armature.select_mirror", + {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("armature.select_hierarchy", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("direction", 'PARENT'), + ("extend", False), + ], + }, + ), + ("armature.select_hierarchy", + {"type": 'LEFT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'PARENT'), + ("extend", True), + ], + }, + ), + ("armature.select_hierarchy", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("direction", 'CHILD'), + ("extend", False), + ], + }, + ), + ("armature.select_hierarchy", + {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'CHILD'), + ("extend", True), + ], + }, + ), + ("armature.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("armature.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("armature.select_similar", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("armature.select_linked", {"type": 'L', "value": 'PRESS'}, None), + ("armature.shortest_path_pick", {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_armature_delete'), + ], + }, + ), + ("wm.call_menu", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_edit_armature_delete'), + ], + }, + ), + ("armature.dissolve", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), + ("armature.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("armature.extrude_move", {"type": 'E', "value": 'PRESS'}, None), + ("armature.extrude_forked", {"type": 'E', "value": 'PRESS', "shift": True}, None), + ("armature.click_extrude", {"type": 'ACTIONMOUSE', "value": 'CLICK', "ctrl": True}, None), + ("armature.fill", {"type": 'F', "value": 'PRESS'}, None), + ("armature.merge", {"type": 'M', "value": 'PRESS', "alt": True}, None), + ("armature.split", {"type": 'Y', "value": 'PRESS'}, None), + ("armature.separate", {"type": 'P', "value": 'PRESS'}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'VIEW3D_MT_bone_options_toggle'), + ], + }, + ), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_bone_options_enable'), + ], + }, + ), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS', "alt": True}, + {"properties": + [("name", 'VIEW3D_MT_bone_options_disable'), + ], + }, + ), + ("armature.layers_show_all", {"type": 'ACCENT_GRAVE', "value": 'PRESS', "ctrl": True}, None), + ("armature.armature_layers", {"type": 'M', "value": 'PRESS', "shift": True}, None), + ("armature.bone_layers", {"type": 'M', "value": 'PRESS'}, None), + ("transform.transform", + {"type": 'S', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("mode", 'BONE_SIZE'), + ], + }, + ), + ("transform.transform", + {"type": 'S', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'BONE_ENVELOPE'), + ], + }, + ), + ("transform.transform", + {"type": 'R', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'BONE_ROLL'), + ], + }, + ), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_armature_specials'), + ], + }, + ), + ], + }, + ), + ("Metaball", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("object.metaball_add", {"type": 'A', "value": 'PRESS', "shift": True}, None), + ("mball.reveal_metaelems", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("mball.hide_metaelems", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("mball.hide_metaelems", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("mball.delete_metaelems", {"type": 'X', "value": 'PRESS'}, None), + ("mball.delete_metaelems", {"type": 'DEL', "value": 'PRESS'}, None), + ("mball.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("mball.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("mball.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("mball.select_similar", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'ENABLED'), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'CONNECTED'), + ], + }, + ), + ], + }, + ), + ("Lattice", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("lattice.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("lattice.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("lattice.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("lattice.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("object.vertex_parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("lattice.flip", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'H', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'VIEW3D_MT_hook'), + ], + }, + ), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'ENABLED'), + ], + }, + ), + ], + }, + ), + ("Particle", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("particle.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("particle.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("particle.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("particle.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("particle.select_linked", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("deselect", False), + ], + }, + ), + ("particle.select_linked", + {"type": 'L', "value": 'PRESS', "shift": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("particle.delete", {"type": 'X', "value": 'PRESS'}, None), + ("particle.delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("particle.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("particle.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("particle.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("particle.brush_edit", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("particle.brush_edit", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, None), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.particle_edit.brush.size'), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path_primary", 'tool_settings.particle_edit.brush.strength'), + ], + }, + ), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'VIEW3D_MT_particle_specials'), + ], + }, + ), + ("particle.weight_set", {"type": 'K', "value": 'PRESS', "shift": True}, None), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'ENABLED'), + ], + }, + ), + ], + }, + ), + ("Font", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("font.style_toggle", + {"type": 'B', "value": 'PRESS', "ctrl": True}, + {"properties": + [("style", 'BOLD'), + ], + }, + ), + ("font.style_toggle", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("style", 'ITALIC'), + ], + }, + ), + ("font.style_toggle", + {"type": 'U', "value": 'PRESS', "ctrl": True}, + {"properties": + [("style", 'UNDERLINE'), + ], + }, + ), + ("font.style_toggle", + {"type": 'P', "value": 'PRESS', "ctrl": True}, + {"properties": + [("style", 'SMALL_CAPS'), + ], + }, + ), + ("font.delete", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_OR_SELECTION'), + ], + }, + ), + ("font.delete", + {"type": 'DEL', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("font.delete", + {"type": 'BACK_SPACE', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_OR_SELECTION'), + ], + }, + ), + ("font.delete", + {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_OR_SELECTION'), + ], + }, + ), + ("font.delete", + {"type": 'BACK_SPACE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("font.move", + {"type": 'HOME', "value": 'PRESS'}, + {"properties": + [("type", 'LINE_BEGIN'), + ], + }, + ), + ("font.move", + {"type": 'END', "value": 'PRESS'}, + {"properties": + [("type", 'LINE_END'), + ], + }, + ), + ("font.move", + {"type": 'LEFT_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("font.move", + {"type": 'RIGHT_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_CHARACTER'), + ], + }, + ), + ("font.move", + {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("font.move", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("font.move", + {"type": 'UP_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_LINE'), + ], + }, + ), + ("font.move", + {"type": 'DOWN_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_LINE'), + ], + }, + ), + ("font.move", + {"type": 'PAGE_UP', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_PAGE'), + ], + }, + ), + ("font.move", + {"type": 'PAGE_DOWN', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_PAGE'), + ], + }, + ), + ("font.move_select", + {"type": 'HOME', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'LINE_BEGIN'), + ], + }, + ), + ("font.move_select", + {"type": 'END', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'LINE_END'), + ], + }, + ), + ("font.move_select", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("font.move_select", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'NEXT_CHARACTER'), + ], + }, + ), + ("font.move_select", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("font.move_select", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("font.move_select", + {"type": 'UP_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_LINE'), + ], + }, + ), + ("font.move_select", + {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'NEXT_LINE'), + ], + }, + ), + ("font.move_select", + {"type": 'PAGE_UP', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_PAGE'), + ], + }, + ), + ("font.move_select", + {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'NEXT_PAGE'), + ], + }, + ), + ("font.change_spacing", + {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("delta", -1), + ], + }, + ), + ("font.change_spacing", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("delta", 1), + ], + }, + ), + ("font.change_character", + {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("delta", 1), + ], + }, + ), + ("font.change_character", + {"type": 'DOWN_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("delta", -1), + ], + }, + ), + ("font.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, None), + ("font.text_copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("font.text_cut", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), + ("font.text_paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("font.line_break", {"type": 'RET', "value": 'PRESS'}, None), + ("font.text_insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None), + ("font.text_insert", + {"type": 'BACK_SPACE', "value": 'PRESS', "alt": True}, + {"properties": + [("accent", True), + ], + }, + ), + ], + }, + ), + ("Object Non-modal", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("object.mode_set", + {"type": 'TAB', "value": 'PRESS'}, + {"properties": + [("mode", 'EDIT'), + ("toggle", True), + ], + }, + ), + ("object.mode_set", + {"type": 'TAB', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'POSE'), + ("toggle", True), + ], + }, + ), + ("object.mode_set", + {"type": 'V', "value": 'PRESS'}, + {"properties": + [("mode", 'VERTEX_PAINT'), + ("toggle", True), + ], + }, + ), + ("object.mode_set", + {"type": 'TAB', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'WEIGHT_PAINT'), + ("toggle", True), + ], + }, + ), + ("object.origin_set", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ], + }, + ), + ("3D View", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("view3d.cursor3d", {"type": 'ACTIONMOUSE', "value": 'CLICK'}, None), + ("view3d.rotate", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("view3d.move", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None), + ("view3d.zoom", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("view3d.dolly", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("view3d.view_selected", + {"type": 'NUMPAD_PERIOD', "value": 'PRESS', "ctrl": True}, + {"properties": + [("use_all_regions", True), + ], + }, + ), + ("view3d.view_selected", + {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, + {"properties": + [("use_all_regions", False), + ], + }, + ), + ("view3d.view_lock_to_active", {"type": 'NUMPAD_PERIOD', "value": 'PRESS', "shift": True}, None), + ("view3d.view_lock_clear", {"type": 'NUMPAD_PERIOD', "value": 'PRESS', "alt": True}, None), + ("view3d.navigate", {"type": 'F', "value": 'PRESS', "shift": True}, None), + ("view3d.smoothview", {"type": 'TIMER1', "value": 'ANY', "any": True}, None), + ("view3d.rotate", {"type": 'TRACKPADPAN', "value": 'ANY'}, None), + ("view3d.rotate", {"type": 'MOUSEROTATE', "value": 'ANY'}, None), + ("view3d.move", {"type": 'TRACKPADPAN', "value": 'ANY', "shift": True}, None), + ("view3d.zoom", {"type": 'TRACKPADZOOM', "value": 'ANY'}, None), + ("view3d.zoom", {"type": 'TRACKPADPAN', "value": 'ANY', "ctrl": True}, None), + ("view3d.zoom", + {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, + {"properties": + [("delta", 1), + ], + }, + ), + ("view3d.zoom", + {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, + {"properties": + [("delta", -1), + ], + }, + ), + ("view3d.zoom", + {"type": 'EQUAL', "value": 'PRESS', "ctrl": True}, + {"properties": + [("delta", 1), + ], + }, + ), + ("view3d.zoom", + {"type": 'MINUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("delta", -1), + ], + }, + ), + ("view3d.zoom", + {"type": 'WHEELINMOUSE', "value": 'PRESS'}, + {"properties": + [("delta", 1), + ], + }, + ), + ("view3d.zoom", + {"type": 'WHEELOUTMOUSE', "value": 'PRESS'}, + {"properties": + [("delta", -1), + ], + }, + ), + ("view3d.dolly", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True}, + {"properties": + [("delta", 1), + ], + }, + ), + ("view3d.dolly", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True}, + {"properties": + [("delta", -1), + ], + }, + ), + ("view3d.dolly", + {"type": 'EQUAL', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("delta", 1), + ], + }, + ), + ("view3d.dolly", + {"type": 'MINUS', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("delta", -1), + ], + }, + ), + ("view3d.zoom_camera_1_to_1", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "shift": True}, None), + ("view3d.view_center_camera", {"type": 'HOME', "value": 'PRESS'}, None), + ("view3d.view_center_lock", {"type": 'HOME', "value": 'PRESS'}, None), + ("view3d.view_center_cursor", {"type": 'HOME', "value": 'PRESS', "alt": True}, None), + ("view3d.view_center_pick", {"type": 'F', "value": 'PRESS', "alt": True}, None), + ("view3d.view_all", + {"type": 'HOME', "value": 'PRESS'}, + {"properties": + [("center", False), + ], + }, + ), + ("view3d.view_all", + {"type": 'HOME', "value": 'PRESS', "ctrl": True}, + {"properties": + [("use_all_regions", True), + ("center", False), + ], + }, + ), + ("view3d.view_all", + {"type": 'C', "value": 'PRESS', "shift": True}, + {"properties": + [("center", True), + ], + }, + ), + ("view3d.view_camera", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + ("view3d.view_axis", + {"type": 'NUMPAD_1', "value": 'PRESS'}, + {"properties": + [("type", 'FRONT'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'NUMPAD_2', "value": 'PRESS'}, + {"properties": + [("type", 'ORBITDOWN'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_3', "value": 'PRESS'}, + {"properties": + [("type", 'RIGHT'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'NUMPAD_4', "value": 'PRESS'}, + {"properties": + [("type", 'ORBITLEFT'), + ], + }, + ), + ("view3d.view_persportho", {"type": 'NUMPAD_5', "value": 'PRESS'}, None), + ("view3d.view_orbit", + {"type": 'NUMPAD_6', "value": 'PRESS'}, + {"properties": + [("type", 'ORBITRIGHT'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_7', "value": 'PRESS'}, + {"properties": + [("type", 'TOP'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'NUMPAD_8', "value": 'PRESS'}, + {"properties": + [("type", 'ORBITUP'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_1', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'BACK'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_3', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'LEFT'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_7', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'BOTTOM'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'NUMPAD_2', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PANDOWN'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'NUMPAD_4', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PANLEFT'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'NUMPAD_6', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PANRIGHT'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'NUMPAD_8', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PANUP'), + ], + }, + ), + ("view3d.view_roll", + {"type": 'NUMPAD_4', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'LEFT'), + ], + }, + ), + ("view3d.view_roll", + {"type": 'NUMPAD_6', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'RIGHT'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'NUMPAD_9', "value": 'PRESS'}, + {"properties": + [("angle", 3.1415927), + ("type", 'ORBITRIGHT'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PANRIGHT'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PANLEFT'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PANUP'), + ], + }, + ), + ("view3d.view_pan", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PANDOWN'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("type", 'ORBITLEFT'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("type", 'ORBITRIGHT'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("type", 'ORBITUP'), + ], + }, + ), + ("view3d.view_orbit", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("type", 'ORBITDOWN'), + ], + }, + ), + ("view3d.view_roll", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'LEFT'), + ], + }, + ), + ("view3d.view_roll", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'RIGHT'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_1', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'FRONT'), + ("align_active", True), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_3', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'RIGHT'), + ("align_active", True), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_7', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'TOP'), + ("align_active", True), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_1', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'BACK'), + ("align_active", True), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_3', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'LEFT'), + ("align_active", True), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NUMPAD_7', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'BOTTOM'), + ("align_active", True), + ], + }, + ), + ("view3d.ndof_orbit_zoom", {"type": 'NDOF_MOTION', "value": 'ANY'}, None), + ("view3d.ndof_orbit", {"type": 'NDOF_MOTION', "value": 'ANY', "ctrl": True}, None), + ("view3d.ndof_pan", {"type": 'NDOF_MOTION', "value": 'ANY', "shift": True}, None), + ("view3d.ndof_all", {"type": 'NDOF_MOTION', "value": 'ANY', "shift": True, "ctrl": True}, None), + ("view3d.view_selected", + {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, + {"properties": + [("use_all_regions", False), + ], + }, + ), + ("view3d.view_roll", + {"type": 'NDOF_BUTTON_ROLL_CCW', "value": 'PRESS'}, + {"properties": + [("type", 'LEFT'), + ], + }, + ), + ("view3d.view_roll", + {"type": 'NDOF_BUTTON_ROLL_CCW', "value": 'PRESS'}, + {"properties": + [("type", 'RIGHT'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_FRONT', "value": 'PRESS'}, + {"properties": + [("type", 'FRONT'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_BACK', "value": 'PRESS'}, + {"properties": + [("type", 'BACK'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_LEFT', "value": 'PRESS'}, + {"properties": + [("type", 'LEFT'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_RIGHT', "value": 'PRESS'}, + {"properties": + [("type", 'RIGHT'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_TOP', "value": 'PRESS'}, + {"properties": + [("type", 'TOP'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_BOTTOM', "value": 'PRESS'}, + {"properties": + [("type", 'BOTTOM'), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_FRONT', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'FRONT'), + ("align_active", True), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_RIGHT', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'RIGHT'), + ("align_active", True), + ], + }, + ), + ("view3d.view_axis", + {"type": 'NDOF_BUTTON_TOP', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'TOP'), + ("align_active", True), + ], + }, + ), + ("view3d.layers", + {"type": 'ACCENT_GRAVE', "value": 'PRESS'}, + {"properties": + [("nr", 0), + ], + }, + ), + ("view3d.layers", + {"type": 'ONE', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 1), + ], + }, + ), + ("view3d.layers", + {"type": 'TWO', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 2), + ], + }, + ), + ("view3d.layers", + {"type": 'THREE', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 3), + ], + }, + ), + ("view3d.layers", + {"type": 'FOUR', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 4), + ], + }, + ), + ("view3d.layers", + {"type": 'FIVE', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 5), + ], + }, + ), + ("view3d.layers", + {"type": 'SIX', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 6), + ], + }, + ), + ("view3d.layers", + {"type": 'SEVEN', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 7), + ], + }, + ), + ("view3d.layers", + {"type": 'EIGHT', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 8), + ], + }, + ), + ("view3d.layers", + {"type": 'NINE', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 9), + ], + }, + ), + ("view3d.layers", + {"type": 'ZERO', "value": 'PRESS', "any": True}, + {"properties": + [("nr", 10), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'Z', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'space_data.shading.type'), + ("value_1", 'SOLID'), + ("value_2", 'TEXTURED'), + ], + }, + ), + ("view3d.toggle_render", {"type": 'Z', "value": 'PRESS', "shift": True}, None), + ("view3d.toggle_xray_draw_option", {"type": 'Z', "value": 'PRESS'}, None), + ("wm.context_toggle", + {"type": 'Z', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.use_occlude_geometry'), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", False), + ("center", False), + ("enumerate", False), + ("object", False), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", True), + ("center", False), + ("enumerate", False), + ("object", False), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", False), + ("center", True), + ("enumerate", False), + ("object", True), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", False), + ("center", False), + ("enumerate", True), + ("object", False), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ("deselect", False), + ("toggle", True), + ("center", True), + ("enumerate", False), + ("object", False), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", False), + ("center", True), + ("enumerate", True), + ("object", False), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", True), + ("center", False), + ("enumerate", True), + ("object", False), + ], + }, + ), + ("view3d.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", True), + ("center", True), + ("enumerate", True), + ("object", False), + ], + }, + ), + ("view3d.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("view3d.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("view3d.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("view3d.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ("view3d.clip_border", {"type": 'B', "value": 'PRESS', "alt": True}, None), + ("view3d.zoom_border", {"type": 'B', "value": 'PRESS', "shift": True}, None), + ("view3d.render_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), + ("view3d.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("view3d.camera_to_view", {"type": 'NUMPAD_0', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("view3d.object_as_camera", {"type": 'NUMPAD_0', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'S', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'VIEW3D_MT_snap'), + ], + }, + ), + ("view3d.copybuffer", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("view3d.pastebuffer", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("wm.context_set_enum", + {"type": 'COMMA', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.transform_pivot_point'), + ("value", 'BOUNDING_BOX_CENTER'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'COMMA', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'tool_settings.transform_pivot_point'), + ("value", 'MEDIAN_POINT'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'COMMA', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'tool_settings.use_transform_pivot_point_align'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.transform_pivot_point'), + ("value", 'CURSOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'tool_settings.transform_pivot_point'), + ("value", 'INDIVIDUAL_ORIGINS'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'tool_settings.transform_pivot_point'), + ("value", 'ACTIVE_ELEMENT'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'SPACE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.show_manipulator'), + ], + }, + ), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("transform.bend", {"type": 'W', "value": 'PRESS', "shift": True}, None), + ("transform.tosphere", {"type": 'S', "value": 'PRESS', "shift": True, "alt": True}, None), + ("transform.shear", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("transform.select_orientation", {"type": 'SPACE', "value": 'PRESS', "alt": True}, None), + ("transform.create_orientation", + {"type": 'SPACE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("use", True), + ], + }, + ), + ("transform.mirror", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ("wm.context_toggle", + {"type": 'TAB', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.use_snap'), + ], + }, + ), + ("wm.context_menu_enum", + {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("data_path", 'tool_settings.snap_element'), + ], + }, + ), + ("object.transform_axis_target", {"type": 'T', "value": 'PRESS', "shift": True}, None), + ("transform.translate", + {"type": 'T', "value": 'PRESS', "shift": True}, + {"properties": + [("texture_space", True), + ], + }, + ), + ("transform.resize", + {"type": 'T', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("texture_space", True), + ], + }, + ), + ("transform.skin_resize", {"type": 'A', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Manipulators", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [], + }, + ), + ("Backdrop Transform Widget", + {"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Backdrop Crop Widget", + {"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Sun Beams Widget", + {"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Corner Pin Widget", + {"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("UV Transform Manipulator", + {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Spot Light Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Area Light Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Target Light Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Force Field Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Camera Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Camera View Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Armature Spline Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("View3D Navigate", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Animation", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("anim.change_frame", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("wm.context_toggle", + {"type": 'T', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.show_seconds'), + ], + }, + ), + ("anim.previewrange_set", {"type": 'P', "value": 'PRESS'}, None), + ("anim.previewrange_clear", {"type": 'P', "value": 'PRESS', "alt": True}, None), + ], + }, + ), + ("Animation Channels", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("anim.channels_click", + {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("anim.channels_click", + {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("children_only", True), + ], + }, + ), + ("anim.channels_rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("anim.channels_rename", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), + ("anim.channel_select_keys", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), + ("anim.channel_select_keys", + {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), + ("anim.channels_select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("anim.channels_select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("anim.channels_select_border", {"type": 'B', "value": 'PRESS'}, None), + ("anim.channels_select_border", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None), + ("anim.channels_delete", {"type": 'X', "value": 'PRESS'}, None), + ("anim.channels_delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("anim.channels_setting_toggle", {"type": 'W', "value": 'PRESS', "shift": True}, None), + ("anim.channels_setting_enable", {"type": 'W', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("anim.channels_setting_disable", {"type": 'W', "value": 'PRESS', "alt": True}, None), + ("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None), + ("anim.channels_expand", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None), + ("anim.channels_collapse", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None), + ("anim.channels_expand", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("all", False), + ], + }, + ), + ("anim.channels_collapse", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("all", False), + ], + }, + ), + ("anim.channels_move", + {"type": 'PAGE_UP', "value": 'PRESS'}, + {"properties": + [("direction", 'UP'), + ], + }, + ), + ("anim.channels_move", + {"type": 'PAGE_DOWN', "value": 'PRESS'}, + {"properties": + [("direction", 'DOWN'), + ], + }, + ), + ("anim.channels_move", + {"type": 'PAGE_UP', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'TOP'), + ], + }, + ), + ("anim.channels_move", + {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'BOTTOM'), + ], + }, + ), + ("anim.channels_group", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), + ("anim.channels_ungroup", {"type": 'G', "value": 'PRESS', "alt": True}, None), + ], + }, + ), + ("UV Editor", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("wm.context_toggle", + {"type": 'Q', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.use_uv_sculpt'), + ], + }, + ), + ("uv.mark_seam", {"type": 'E', "value": 'PRESS', "ctrl": True}, None), + ("uv.select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("uv.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("uv.select_loop", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("uv.select_loop", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("uv.select_split", {"type": 'Y', "value": 'PRESS'}, None), + ("uv.select_border", + {"type": 'B', "value": 'PRESS'}, + {"properties": + [("pinned", False), + ], + }, + ), + ("uv.select_border", + {"type": 'B', "value": 'PRESS', "ctrl": True}, + {"properties": + [("pinned", True), + ], + }, + ), + ("uv.circle_select", {"type": 'C', "value": 'PRESS'}, None), + ("uv.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("uv.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("uv.select_linked", + {"type": 'L', "value": 'PRESS', "ctrl": True}, + {"properties": + [("extend", True), + ("deselect", False), + ], + }, + ), + ("uv.select_linked_pick", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("extend", True), + ("deselect", False), + ], + }, + ), + ("uv.select_linked", + {"type": 'L', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", False), + ("deselect", True), + ], + }, + ), + ("uv.select_linked_pick", + {"type": 'L', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", False), + ("deselect", True), + ], + }, + ), + ("uv.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("uv.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("uv.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("uv.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("uv.select_pinned", {"type": 'P', "value": 'PRESS', "shift": True}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'IMAGE_MT_uvs_weldalign'), + ], + }, + ), + ("uv.stitch", {"type": 'V', "value": 'PRESS'}, None), + ("uv.pin", + {"type": 'P', "value": 'PRESS'}, + {"properties": + [("clear", False), + ], + }, + ), + ("uv.pin", + {"type": 'P', "value": 'PRESS', "alt": True}, + {"properties": + [("clear", True), + ], + }, + ), + ("uv.unwrap", {"type": 'E', "value": 'PRESS'}, None), + ("uv.minimize_stretch", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("uv.pack_islands", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("uv.average_islands_scale", {"type": 'A', "value": 'PRESS', "ctrl": True}, None), + ("uv.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("uv.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("uv.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("uv.cursor_set", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("wm.call_menu", + {"type": 'S', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'IMAGE_MT_uvs_snap'), + ], + }, + ), + ("wm.call_menu", + {"type": 'TAB', "value": 'PRESS', "ctrl": True}, + {"properties": + [("name", 'IMAGE_MT_uvs_select_mode'), + ], + }, + ), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.proportional_edit'), + ("value_1", 'DISABLED'), + ("value_2", 'ENABLED'), + ], + }, + ), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("transform.shear", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("transform.mirror", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ("wm.context_toggle", + {"type": 'TAB', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.use_snap'), + ], + }, + ), + ("wm.context_menu_enum", + {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("data_path", 'tool_settings.snap_uv_element'), + ], + }, + ), + ], + }, + ), + ("UV Sculpt", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("wm.context_toggle", + {"type": 'Q', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.use_uv_sculpt'), + ], + }, + ), + ("sculpt.uv_sculpt_stroke", + {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": + [("mode", 'NORMAL'), + ], + }, + ), + ("sculpt.uv_sculpt_stroke", + {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'INVERT'), + ], + }, + ), + ("sculpt.uv_sculpt_stroke", + {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'RELAX'), + ], + }, + ), + ("brush.scale_size", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 0.9), + ], + }, + ), + ("brush.scale_size", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("scalar", 1.1111112), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("data_path_primary", 'tool_settings.uv_sculpt.brush.size'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.size'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_size'), + ("rotation_path", 'tool_settings.uv_sculpt.brush.texture_slot.angle'), + ("color_path", 'tool_settings.uv_sculpt.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.uv_sculpt.brush'), + ("secondary_tex", False), + ], + }, + ), + ("wm.radial_control", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path_primary", 'tool_settings.uv_sculpt.brush.strength'), + ("data_path_secondary", 'tool_settings.unified_paint_settings.strength'), + ("use_secondary", 'tool_settings.unified_paint_settings.use_unified_strength'), + ("rotation_path", 'tool_settings.uv_sculpt.brush.texture_slot.angle'), + ("color_path", 'tool_settings.uv_sculpt.brush.cursor_color_add'), + ("fill_color_path", ''), + ("fill_color_override_path", ''), + ("fill_color_override_test_path", ''), + ("zoom_path", ''), + ("image_id", 'tool_settings.uv_sculpt.brush'), + ("secondary_tex", False), + ], + }, + ), + ("brush.uv_sculpt_tool_set", + {"type": 'S', "value": 'PRESS'}, + {"properties": + [("tool", 'RELAX'), + ], + }, + ), + ("brush.uv_sculpt_tool_set", + {"type": 'P', "value": 'PRESS'}, + {"properties": + [("tool", 'PINCH'), + ], + }, + ), + ("brush.uv_sculpt_tool_set", + {"type": 'G', "value": 'PRESS'}, + {"properties": + [("tool", 'GRAB'), + ], + }, + ), + ], + }, + ), + ("Mask Editing", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("mask.new", {"type": 'N', "value": 'PRESS', "alt": True}, None), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'MASK_MT_add'), + ], + }, + ), + ("wm.context_cycle_enum", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.proportional_edit_falloff'), + ("wrap", True), + ], + }, + ), + ("wm.context_toggle", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.use_proportional_edit_mask'), + ], + }, + ), + ("mask.add_vertex_slide", {"type": 'ACTIONMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("mask.add_feather_vertex_slide", {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True}, None), + ("mask.delete", {"type": 'X', "value": 'PRESS'}, None), + ("mask.delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("mask.select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", False), + ], + }, + ), + ("mask.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", False), + ("deselect", False), + ("toggle", True), + ], + }, + ), + ("mask.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("mask.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("mask.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("mask.select_linked_pick", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("deselect", False), + ], + }, + ), + ("mask.select_linked_pick", + {"type": 'L', "value": 'PRESS', "shift": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("mask.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("mask.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ("mask.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True, "alt": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("mask.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("mask.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("mask.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("mask.hide_view_clear", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("mask.hide_view_set", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("mask.hide_view_set", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("clip.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("mask.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None), + ("mask.slide_point", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("mask.slide_spline_curvature", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("mask.handle_type_set", {"type": 'V', "value": 'PRESS'}, None), + ("mask.normals_make_consistent", {"type": 'N', "value": 'PRESS', "ctrl": True}, None), + ("mask.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("mask.parent_clear", {"type": 'P', "value": 'PRESS', "alt": True}, None), + ("mask.shape_key_insert", {"type": 'I', "value": 'PRESS'}, None), + ("mask.shape_key_clear", {"type": 'I', "value": 'PRESS', "alt": True}, None), + ("mask.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("mask.copy_splines", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("mask.paste_splines", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("uv.cursor_set", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("transform.transform", + {"type": 'S', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'MASK_SHRINKFATTEN'), + ], + }, + ), + ], + }, + ), + ("Markers", + {"space_type": 'EMPTY', "region_type": 'WINDOW'}, + {"items": + [("marker.add", {"type": 'M', "value": 'PRESS'}, None), + ("marker.move", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("marker.duplicate", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("marker.select", {"type": 'SELECTMOUSE', "value": 'PRESS'}, None), + ("marker.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("marker.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("extend", False), + ("camera", True), + ], + }, + ), + ("marker.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ("camera", True), + ], + }, + ), + ("marker.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("marker.select_all", {"type": 'A', "value": 'PRESS'}, None), + ("marker.delete", {"type": 'X', "value": 'PRESS'}, None), + ("marker.delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ("marker.move", {"type": 'G', "value": 'PRESS'}, None), + ("marker.camera_bind", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Graph Editor Generic", + {"space_type": 'GRAPH_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("graph.properties", {"type": 'N', "value": 'PRESS'}, None), + ("graph.extrapolation_type", {"type": 'E', "value": 'PRESS', "shift": True}, None), + ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), + ("graph.hide", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("graph.hide", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("graph.reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ], + }, + ), + ("Graph Editor", + {"space_type": 'GRAPH_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("wm.context_toggle", + {"type": 'H', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.show_handles'), + ], + }, + ), + ("graph.cursor_set", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("graph.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ("column", False), + ("curves", False), + ], + }, + ), + ("graph.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ("column", True), + ("curves", False), + ], + }, + ), + ("graph.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ("column", False), + ("curves", False), + ], + }, + ), + ("graph.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", True), + ("column", True), + ("curves", False), + ], + }, + ), + ("graph.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ("column", False), + ("curves", True), + ], + }, + ), + ("graph.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("extend", True), + ("column", False), + ("curves", True), + ], + }, + ), + ("graph.select_leftright", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'CHECK'), + ("extend", False), + ], + }, + ), + ("graph.select_leftright", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("mode", 'CHECK'), + ("extend", True), + ], + }, + ), + ("graph.select_leftright", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("mode", 'LEFT'), + ("extend", False), + ], + }, + ), + ("graph.select_leftright", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("mode", 'RIGHT'), + ("extend", False), + ], + }, + ), + ("graph.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("graph.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("graph.select_border", + {"type": 'B', "value": 'PRESS'}, + {"properties": + [("axis_range", False), + ("include_handles", False), + ], + }, + ), + ("graph.select_border", + {"type": 'B', "value": 'PRESS', "alt": True}, + {"properties": + [("axis_range", True), + ("include_handles", False), + ], + }, + ), + ("graph.select_border", + {"type": 'B', "value": 'PRESS', "ctrl": True}, + {"properties": + [("axis_range", False), + ("include_handles", True), + ], + }, + ), + ("graph.select_border", + {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("axis_range", True), + ("include_handles", True), + ], + }, + ), + ("graph.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("graph.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("graph.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ("graph.select_column", + {"type": 'K', "value": 'PRESS'}, + {"properties": + [("mode", 'KEYS'), + ], + }, + ), + ("graph.select_column", + {"type": 'K', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'CFRA'), + ], + }, + ), + ("graph.select_column", + {"type": 'K', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'MARKERS_COLUMN'), + ], + }, + ), + ("graph.select_column", + {"type": 'K', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'MARKERS_BETWEEN'), + ], + }, + ), + ("graph.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("graph.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("graph.select_linked", {"type": 'L', "value": 'PRESS'}, None), + ("graph.frame_jump", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), + ("graph.snap", {"type": 'S', "value": 'PRESS', "shift": True}, None), + ("graph.mirror", {"type": 'M', "value": 'PRESS', "shift": True}, None), + ("graph.handle_type", {"type": 'V', "value": 'PRESS'}, None), + ("graph.interpolation_type", {"type": 'T', "value": 'PRESS'}, None), + ("graph.easing_type", {"type": 'E', "value": 'PRESS', "ctrl": True}, None), + ("graph.smooth", {"type": 'O', "value": 'PRESS', "alt": True}, None), + ("graph.sample", {"type": 'O', "value": 'PRESS', "shift": True}, None), + ("graph.bake", {"type": 'C', "value": 'PRESS', "alt": True}, None), + ("wm.call_menu", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("name", 'GRAPH_MT_delete'), + ], + }, + ), + ("wm.call_menu", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("name", 'GRAPH_MT_delete'), + ], + }, + ), + ("graph.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("graph.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), + ("graph.click_insert", + {"type": 'ACTIONMOUSE', "value": 'CLICK', "ctrl": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("graph.click_insert", + {"type": 'ACTIONMOUSE', "value": 'CLICK', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("graph.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("graph.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("graph.paste", + {"type": 'V', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("flipped", True), + ], + }, + ), + ("graph.previewrange_set", {"type": 'P', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("graph.view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("graph.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("graph.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("graph.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + ("graph.fmodifier_add", + {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("only_active", False), + ], + }, + ), + ("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.transform", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("mode", 'TIME_EXTEND'), + ], + }, + ), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("wm.context_toggle", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.use_proportional_fcurve'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'COMMA', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'BOUNDING_BOX_CENTER'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'CURSOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'INDIVIDUAL_ORIGINS'), + ], + }, + ), + ("marker.add", {"type": 'M', "value": 'PRESS'}, None), + ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Image Generic", + {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("image.new", {"type": 'N', "value": 'PRESS', "alt": True}, None), + ("image.open", {"type": 'O', "value": 'PRESS', "alt": True}, None), + ("image.reload", {"type": 'R', "value": 'PRESS', "alt": True}, None), + ("image.read_viewlayers", {"type": 'R', "value": 'PRESS', "ctrl": True}, None), + ("image.save", {"type": 'S', "value": 'PRESS', "alt": True}, None), + ("image.save_as", {"type": 'F3', "value": 'PRESS'}, None), + ("image.properties", {"type": 'N', "value": 'PRESS'}, None), + ("image.toolshelf", {"type": 'T', "value": 'PRESS'}, None), + ("image.cycle_render_slot", {"type": 'J', "value": 'PRESS'}, None), + ("image.cycle_render_slot", + {"type": 'J', "value": 'PRESS', "alt": True}, + {"properties": + [("reverse", True), + ], + }, + ), + ], + }, + ), + ("Image", + {"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("image.view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("image.view_all", + {"type": 'HOME', "value": 'PRESS', "shift": True}, + {"properties": + [("fit_view", True), + ], + }, + ), + ("image.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("image.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None), + ("image.view_pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None), + ("image.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("image.view_ndof", {"type": 'NDOF_MOTION', "value": 'ANY'}, None), + ("image.view_zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS'}, None), + ("image.view_zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS'}, None), + ("image.view_zoom_in", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None), + ("image.view_zoom_out", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None), + ("image.view_zoom", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("image.view_zoom", {"type": 'TRACKPADZOOM', "value": 'ANY'}, None), + ("image.view_zoom", {"type": 'TRACKPADPAN', "value": 'ANY', "ctrl": True}, None), + ("image.view_zoom_border", {"type": 'B', "value": 'PRESS', "shift": True}, None), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_8', "value": 'PRESS', "ctrl": True}, + {"properties": + [("ratio", 8.0), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_4', "value": 'PRESS', "ctrl": True}, + {"properties": + [("ratio", 4.0), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_2', "value": 'PRESS', "ctrl": True}, + {"properties": + [("ratio", 2.0), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_8', "value": 'PRESS', "shift": True}, + {"properties": + [("ratio", 8.0), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_4', "value": 'PRESS', "shift": True}, + {"properties": + [("ratio", 4.0), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_2', "value": 'PRESS', "shift": True}, + {"properties": + [("ratio", 2.0), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_1', "value": 'PRESS'}, + {"properties": + [("ratio", 1.0), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_2', "value": 'PRESS'}, + {"properties": + [("ratio", 0.5), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_4', "value": 'PRESS'}, + {"properties": + [("ratio", 0.25), + ], + }, + ), + ("image.view_zoom_ratio", + {"type": 'NUMPAD_8', "value": 'PRESS'}, + {"properties": + [("ratio", 0.125), + ], + }, + ), + ("image.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("image.sample", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("image.curves_point_set", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("point", 'BLACK_POINT'), + ], + }, + ), + ("image.curves_point_set", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("point", 'WHITE_POINT'), + ], + }, + ), + ("object.mode_set", + {"type": 'TAB', "value": 'PRESS'}, + {"properties": + [("mode", 'EDIT'), + ("toggle", True), + ], + }, + ), + ("wm.context_set_int", + {"type": 'ONE', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 0), + ], + }, + ), + ("wm.context_set_int", + {"type": 'TWO', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 1), + ], + }, + ), + ("wm.context_set_int", + {"type": 'THREE', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 2), + ], + }, + ), + ("wm.context_set_int", + {"type": 'FOUR', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 3), + ], + }, + ), + ("wm.context_set_int", + {"type": 'FIVE', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 4), + ], + }, + ), + ("wm.context_set_int", + {"type": 'SIX', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 5), + ], + }, + ), + ("wm.context_set_int", + {"type": 'SEVEN', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 6), + ], + }, + ), + ("wm.context_set_int", + {"type": 'EIGHT', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.image.render_slots.active_index'), + ("value", 7), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'COMMA', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'CENTER'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'COMMA', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'MEDIAN'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'CURSOR'), + ], + }, + ), + ("image.render_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), + ("image.clear_render_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ], + }, + ), + ("Node Generic", + {"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("node.properties", {"type": 'N', "value": 'PRESS'}, None), + ("node.toolbar", {"type": 'T', "value": 'PRESS'}, None), + ], + }, + ), + ("Node Editor", + {"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select", + {"type": 'ACTIONMOUSE', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select_border", + {"type": 'EVT_TWEAK_S', "value": 'ANY'}, + {"properties": + [("tweak", True), + ], + }, + ), + ("node.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True, "alt": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("node.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("node.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ("node.link", + {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": + [("detach", False), + ], + }, + ), + ("node.link", + {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("detach", True), + ], + }, + ), + ("node.resize", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("node.add_reroute", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, None), + ("node.links_cut", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("node.select_link_viewer", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("node.backimage_move", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "alt": True}, None), + ("node.backimage_zoom", + {"type": 'V', "value": 'PRESS'}, + {"properties": + [("factor", 0.8333333), + ], + }, + ), + ("node.backimage_zoom", + {"type": 'V', "value": 'PRESS', "alt": True}, + {"properties": + [("factor", 1.2), + ], + }, + ), + ("node.backimage_fit", {"type": 'HOME', "value": 'PRESS', "alt": True}, None), + ("node.backimage_sample", {"type": 'ACTIONMOUSE', "value": 'PRESS', "alt": True}, None), + ("node.link_make", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("replace", False), + ], + }, + ), + ("node.link_make", + {"type": 'F', "value": 'PRESS', "shift": True}, + {"properties": + [("replace", True), + ], + }, + ), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'NODE_MT_add'), + ], + }, + ), + ("node.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("node.duplicate_move_keep_inputs", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("node.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None), + ("node.detach", {"type": 'P', "value": 'PRESS', "alt": True}, None), + ("node.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None), + ("node.hide_toggle", {"type": 'H', "value": 'PRESS'}, None), + ("node.mute_toggle", {"type": 'M', "value": 'PRESS'}, None), + ("node.preview_toggle", {"type": 'H', "value": 'PRESS', "shift": True}, None), + ("node.hide_socket_toggle", {"type": 'H', "value": 'PRESS', "ctrl": True}, None), + ("node.view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("node.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("node.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("node.select_border", + {"type": 'B', "value": 'PRESS'}, + {"properties": + [("tweak", False), + ], + }, + ), + ("node.delete", {"type": 'X', "value": 'PRESS'}, None), + ("node.delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("node.delete_reconnect", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), + ("node.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("node.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("node.select_linked_to", {"type": 'L', "value": 'PRESS', "shift": True}, None), + ("node.select_linked_from", {"type": 'L', "value": 'PRESS'}, None), + ("node.select_grouped", + {"type": 'G', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", False), + ], + }, + ), + ("node.select_grouped", + {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("node.select_same_type_step", + {"type": 'RIGHT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("prev", False), + ], + }, + ), + ("node.select_same_type_step", + {"type": 'LEFT_BRACKET', "value": 'PRESS', "shift": True}, + {"properties": + [("prev", True), + ], + }, + ), + ("node.find_node", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), + ("node.group_make", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), + ("node.group_ungroup", {"type": 'G', "value": 'PRESS', "alt": True}, None), + ("node.group_separate", {"type": 'P', "value": 'PRESS'}, None), + ("node.group_edit", + {"type": 'TAB', "value": 'PRESS'}, + {"properties": + [("exit", False), + ], + }, + ), + ("node.group_edit", + {"type": 'TAB', "value": 'PRESS', "ctrl": True}, + {"properties": + [("exit", True), + ], + }, + ), + ("node.read_viewlayers", {"type": 'R', "value": 'PRESS', "ctrl": True}, None), + ("node.render_changed", {"type": 'Z', "value": 'PRESS'}, None), + ("node.clipboard_copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("node.clipboard_paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("node.viewer_border", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), + ("node.clear_viewer_border", {"type": 'B', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("node.translate_attach", {"type": 'G', "value": 'PRESS'}, None), + ("node.translate_attach", {"type": 'EVT_TWEAK_A', "value": 'ANY'}, None), + ("node.translate_attach", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.translate", + {"type": 'G', "value": 'PRESS'}, + {"properties": + [("release_confirm", True), + ], + }, + ), + ("transform.translate", + {"type": 'EVT_TWEAK_A', "value": 'ANY'}, + {"properties": + [("release_confirm", True), + ], + }, + ), + ("transform.translate", + {"type": 'EVT_TWEAK_S', "value": 'ANY'}, + {"properties": + [("release_confirm", True), + ], + }, + ), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("node.move_detach_links", {"type": 'D', "value": 'PRESS', "alt": True}, None), + ("node.move_detach_links_release", {"type": 'EVT_TWEAK_A', "value": 'ANY', "alt": True}, None), + ("node.move_detach_links", {"type": 'EVT_TWEAK_S', "value": 'ANY', "alt": True}, None), + ("wm.context_toggle", + {"type": 'TAB', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'tool_settings.use_snap'), + ], + }, + ), + ("wm.context_menu_enum", + {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("data_path", 'tool_settings.snap_node_element'), + ], + }, + ), + ], + }, + ), + ("File Browser", + {"space_type": 'FILE_BROWSER', "region_type": 'WINDOW'}, + {"items": + [("file.parent", {"type": 'UP_ARROW', "value": 'PRESS', "alt": True}, None), + ("file.previous", {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, None), + ("file.next", {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, None), + ("file.refresh", {"type": 'R', "value": 'PRESS'}, None), + ("file.parent", {"type": 'P', "value": 'PRESS'}, None), + ("file.previous", {"type": 'BACK_SPACE', "value": 'PRESS'}, None), + ("file.next", {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, None), + ("wm.context_toggle", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.params.show_hidden'), + ], + }, + ), + ("file.directory_new", {"type": 'I', "value": 'PRESS'}, None), + ("file.delete", {"type": 'X', "value": 'PRESS'}, None), + ("file.delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None), + ("file.bookmark_toggle", {"type": 'T', "value": 'PRESS'}, None), + ("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("File Browser Main", + {"space_type": 'FILE_BROWSER', "region_type": 'WINDOW'}, + {"items": + [("file.execute", + {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, + {"properties": + [("need_active", True), + ], + }, + ), + ("file.refresh", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'}, None), + ("file.select", + {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("file.select", + {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ("fill", True), + ], + }, + ), + ("file.select", + {"type": 'RIGHTMOUSE', "value": 'CLICK'}, + {"properties": + [("open", False), + ], + }, + ), + ("file.select", + {"type": 'RIGHTMOUSE', "value": 'CLICK', "shift": True}, + {"properties": + [("extend", True), + ("open", False), + ], + }, + ), + ("file.select", + {"type": 'RIGHTMOUSE', "value": 'CLICK', "alt": True}, + {"properties": + [("extend", True), + ("fill", True), + ("open", False), + ], + }, + ), + ("file.select_walk", + {"type": 'UP_ARROW', "value": 'PRESS'}, + {"properties": + [("direction", 'UP'), + ], + }, + ), + ("file.select_walk", + {"type": 'UP_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'UP'), + ("extend", True), + ], + }, + ), + ("file.select_walk", + {"type": 'UP_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("direction", 'UP'), + ("extend", True), + ("fill", True), + ], + }, + ), + ("file.select_walk", + {"type": 'DOWN_ARROW', "value": 'PRESS'}, + {"properties": + [("direction", 'DOWN'), + ], + }, + ), + ("file.select_walk", + {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'DOWN'), + ("extend", True), + ], + }, + ), + ("file.select_walk", + {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("direction", 'DOWN'), + ("extend", True), + ("fill", True), + ], + }, + ), + ("file.select_walk", + {"type": 'LEFT_ARROW', "value": 'PRESS'}, + {"properties": + [("direction", 'LEFT'), + ], + }, + ), + ("file.select_walk", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'LEFT'), + ("extend", True), + ], + }, + ), + ("file.select_walk", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("direction", 'LEFT'), + ("extend", True), + ("fill", True), + ], + }, + ), + ("file.select_walk", + {"type": 'RIGHT_ARROW', "value": 'PRESS'}, + {"properties": + [("direction", 'RIGHT'), + ], + }, + ), + ("file.select_walk", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("direction", 'RIGHT'), + ("extend", True), + ], + }, + ), + ("file.select_walk", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("direction", 'RIGHT'), + ("extend", True), + ("fill", True), + ], + }, + ), + ("file.previous", {"type": 'BUTTON4MOUSE', "value": 'CLICK'}, None), + ("file.next", {"type": 'BUTTON5MOUSE', "value": 'CLICK'}, None), + ("file.select_all_toggle", {"type": 'A', "value": 'PRESS'}, None), + ("file.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("file.select_border", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None), + ("file.rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("file.highlight", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None), + ("file.filenum", + {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, + {"properties": + [("increment", 1), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True}, + {"properties": + [("increment", 10), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("increment", 100), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, + {"properties": + [("increment", -1), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True}, + {"properties": + [("increment", -10), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("increment", -100), + ], + }, + ), + ], + }, + ), + ("File Browser Buttons", + {"space_type": 'FILE_BROWSER', "region_type": 'WINDOW'}, + {"items": + [("file.filenum", + {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, + {"properties": + [("increment", 1), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True}, + {"properties": + [("increment", 10), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("increment", 100), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, + {"properties": + [("increment", -1), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "shift": True}, + {"properties": + [("increment", -10), + ], + }, + ), + ("file.filenum", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("increment", -100), + ], + }, + ), + ], + }, + ), + ("Dopesheet Generic", + {"space_type": 'DOPESHEET_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("action.properties", {"type": 'N', "value": 'PRESS'}, None), + ], + }, + ), + ("Dopesheet", + {"space_type": 'DOPESHEET_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("action.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ("column", False), + ("channel", False), + ], + }, + ), + ("action.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ("column", True), + ("channel", False), + ], + }, + ), + ("action.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ("column", False), + ("channel", False), + ], + }, + ), + ("action.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", True), + ("column", True), + ("channel", False), + ], + }, + ), + ("action.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, + {"properties": + [("extend", False), + ("column", False), + ("channel", True), + ], + }, + ), + ("action.clickselect", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("extend", True), + ("column", False), + ("channel", True), + ], + }, + ), + ("action.select_leftright", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'CHECK'), + ("extend", False), + ], + }, + ), + ("action.select_leftright", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("mode", 'CHECK'), + ("extend", True), + ], + }, + ), + ("action.select_leftright", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("mode", 'LEFT'), + ("extend", False), + ], + }, + ), + ("action.select_leftright", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("mode", 'RIGHT'), + ("extend", False), + ], + }, + ), + ("action.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("action.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("action.select_border", + {"type": 'B', "value": 'PRESS'}, + {"properties": + [("axis_range", False), + ], + }, + ), + ("action.select_border", + {"type": 'B', "value": 'PRESS', "alt": True}, + {"properties": + [("axis_range", True), + ], + }, + ), + ("action.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("action.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("action.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ("action.select_column", + {"type": 'K', "value": 'PRESS'}, + {"properties": + [("mode", 'KEYS'), + ], + }, + ), + ("action.select_column", + {"type": 'K', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'CFRA'), + ], + }, + ), + ("action.select_column", + {"type": 'K', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'MARKERS_COLUMN'), + ], + }, + ), + ("action.select_column", + {"type": 'K', "value": 'PRESS', "alt": True}, + {"properties": + [("mode", 'MARKERS_BETWEEN'), + ], + }, + ), + ("action.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("action.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("action.select_linked", {"type": 'L', "value": 'PRESS'}, None), + ("action.frame_jump", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), + ("action.snap", {"type": 'S', "value": 'PRESS', "shift": True}, None), + ("action.mirror", {"type": 'M', "value": 'PRESS', "shift": True}, None), + ("action.handle_type", {"type": 'V', "value": 'PRESS'}, None), + ("action.interpolation_type", {"type": 'T', "value": 'PRESS'}, None), + ("action.extrapolation_type", {"type": 'E', "value": 'PRESS', "shift": True}, None), + ("action.keyframe_type", {"type": 'R', "value": 'PRESS'}, None), + ("action.sample", {"type": 'O', "value": 'PRESS', "shift": True}, None), + ("wm.call_menu", + {"type": 'X', "value": 'PRESS'}, + {"properties": + [("name", 'DOPESHEET_MT_delete'), + ], + }, + ), + ("wm.call_menu", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("name", 'DOPESHEET_MT_delete'), + ], + }, + ), + ("action.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("action.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), + ("action.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("action.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("action.paste", + {"type": 'V', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("flipped", True), + ], + }, + ), + ("action.previewrange_set", {"type": 'P', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("action.view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("action.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("action.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("action.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + ("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None), + ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), + ("transform.transform", + {"type": 'G', "value": 'PRESS'}, + {"properties": + [("mode", 'TIME_TRANSLATE'), + ], + }, + ), + ("transform.transform", + {"type": 'EVT_TWEAK_S', "value": 'ANY'}, + {"properties": + [("mode", 'TIME_TRANSLATE'), + ], + }, + ), + ("transform.transform", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("mode", 'TIME_EXTEND'), + ], + }, + ), + ("transform.transform", + {"type": 'S', "value": 'PRESS'}, + {"properties": + [("mode", 'TIME_SCALE'), + ], + }, + ), + ("transform.transform", + {"type": 'T', "value": 'PRESS', "shift": True}, + {"properties": + [("mode", 'TIME_SLIDE'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'tool_settings.use_proportional_action'), + ], + }, + ), + ("marker.add", {"type": 'M', "value": 'PRESS'}, None), + ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("NLA Generic", + {"space_type": 'NLA_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("nla.properties", {"type": 'N', "value": 'PRESS'}, None), + ("nla.tweakmode_enter", {"type": 'TAB', "value": 'PRESS'}, None), + ("nla.tweakmode_exit", {"type": 'TAB', "value": 'PRESS'}, None), + ("nla.tweakmode_enter", + {"type": 'TAB', "value": 'PRESS', "shift": True}, + {"properties": + [("isolate_action", True), + ], + }, + ), + ("nla.tweakmode_exit", + {"type": 'TAB', "value": 'PRESS', "shift": True}, + {"properties": + [("isolate_action", True), + ], + }, + ), + ("anim.channels_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("NLA Channels", + {"space_type": 'NLA_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("nla.channels_click", + {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("nla.channels_click", + {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("nla.tracks_add", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("above_selected", False), + ], + }, + ), + ("nla.tracks_add", + {"type": 'A', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("above_selected", True), + ], + }, + ), + ("nla.tracks_delete", {"type": 'X', "value": 'PRESS'}, None), + ("nla.tracks_delete", {"type": 'DEL', "value": 'PRESS'}, None), + ], + }, + ), + ("NLA Editor", + {"space_type": 'NLA_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("nla.click_select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("nla.click_select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("nla.select_leftright", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("mode", 'CHECK'), + ("extend", False), + ], + }, + ), + ("nla.select_leftright", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("mode", 'CHECK'), + ("extend", True), + ], + }, + ), + ("nla.select_leftright", + {"type": 'LEFT_BRACKET', "value": 'PRESS'}, + {"properties": + [("mode", 'LEFT'), + ("extend", False), + ], + }, + ), + ("nla.select_leftright", + {"type": 'RIGHT_BRACKET', "value": 'PRESS'}, + {"properties": + [("mode", 'RIGHT'), + ("extend", False), + ], + }, + ), + ("nla.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("nla.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("nla.select_border", + {"type": 'B', "value": 'PRESS'}, + {"properties": + [("axis_range", False), + ], + }, + ), + ("nla.select_border", + {"type": 'B', "value": 'PRESS', "alt": True}, + {"properties": + [("axis_range", True), + ], + }, + ), + ("nla.previewrange_set", {"type": 'P', "value": 'PRESS', "ctrl": True, "alt": True}, None), + ("nla.view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("nla.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("nla.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("nla.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + ("nla.actionclip_add", {"type": 'A', "value": 'PRESS', "shift": True}, None), + ("nla.transition_add", {"type": 'T', "value": 'PRESS', "shift": True}, None), + ("nla.soundclip_add", {"type": 'K', "value": 'PRESS', "shift": True}, None), + ("nla.meta_add", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("nla.meta_remove", {"type": 'G', "value": 'PRESS', "alt": True}, None), + ("nla.duplicate", + {"type": 'D', "value": 'PRESS', "shift": True}, + {"properties": + [("linked", False), + ], + }, + ), + ("nla.duplicate", + {"type": 'D', "value": 'PRESS', "alt": True}, + {"properties": + [("linked", True), + ], + }, + ), + ("nla.make_single_user", {"type": 'U', "value": 'PRESS'}, None), + ("nla.delete", {"type": 'X', "value": 'PRESS'}, None), + ("nla.delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("nla.split", {"type": 'Y', "value": 'PRESS'}, None), + ("nla.mute_toggle", {"type": 'H', "value": 'PRESS'}, None), + ("nla.swap", {"type": 'F', "value": 'PRESS', "alt": True}, None), + ("nla.move_up", {"type": 'PAGE_UP', "value": 'PRESS'}, None), + ("nla.move_down", {"type": 'PAGE_DOWN', "value": 'PRESS'}, None), + ("nla.apply_scale", {"type": 'A', "value": 'PRESS', "ctrl": True}, None), + ("nla.clear_scale", {"type": 'S', "value": 'PRESS', "alt": True}, None), + ("nla.snap", {"type": 'S', "value": 'PRESS', "shift": True}, None), + ("nla.fmodifier_add", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("transform.transform", + {"type": 'G', "value": 'PRESS'}, + {"properties": + [("mode", 'TRANSLATION'), + ], + }, + ), + ("transform.transform", + {"type": 'EVT_TWEAK_S', "value": 'ANY'}, + {"properties": + [("mode", 'TRANSLATION'), + ], + }, + ), + ("transform.transform", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("mode", 'TIME_EXTEND'), + ], + }, + ), + ("transform.transform", + {"type": 'S', "value": 'PRESS'}, + {"properties": + [("mode", 'TIME_SCALE'), + ], + }, + ), + ("marker.add", {"type": 'M', "value": 'PRESS'}, None), + ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Text Generic", + {"space_type": 'TEXT_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("text.start_find", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), + ("text.jump", {"type": 'J', "value": 'PRESS', "ctrl": True}, None), + ("text.find", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), + ("text.replace", {"type": 'H', "value": 'PRESS', "ctrl": True}, None), + ("text.properties", {"type": 'T', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Text", + {"space_type": 'TEXT_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("wm.context_cycle_int", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", False), + ], + }, + ), + ("wm.context_cycle_int", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", True), + ], + }, + ), + ("wm.context_cycle_int", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", False), + ], + }, + ), + ("wm.context_cycle_int", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", True), + ], + }, + ), + ("text.new", {"type": 'N', "value": 'PRESS', "ctrl": True}, None), + ("text.open", {"type": 'O', "value": 'PRESS', "alt": True}, None), + ("text.reload", {"type": 'R', "value": 'PRESS', "alt": True}, None), + ("text.save", {"type": 'S', "value": 'PRESS', "alt": True}, None), + ("text.save_as", {"type": 'S', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True}, None), + ("text.run_script", {"type": 'P', "value": 'PRESS', "alt": True}, None), + ("text.cut", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), + ("text.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("text.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("text.cut", {"type": 'DEL', "value": 'PRESS', "shift": True}, None), + ("text.copy", {"type": 'INSERT', "value": 'PRESS', "ctrl": True}, None), + ("text.paste", {"type": 'INSERT', "value": 'PRESS', "shift": True}, None), + ("text.duplicate_line", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), + ("text.select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, None), + ("text.select_line", {"type": 'A', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("text.select_word", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), + ("text.move_lines", + {"type": 'UP_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("direction", 'UP'), + ], + }, + ), + ("text.move_lines", + {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("direction", 'DOWN'), + ], + }, + ), + ("text.indent", {"type": 'TAB', "value": 'PRESS'}, None), + ("text.unindent", {"type": 'TAB', "value": 'PRESS', "shift": True}, None), + ("text.uncomment", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("text.move", + {"type": 'HOME', "value": 'PRESS'}, + {"properties": + [("type", 'LINE_BEGIN'), + ], + }, + ), + ("text.move", + {"type": 'END', "value": 'PRESS'}, + {"properties": + [("type", 'LINE_END'), + ], + }, + ), + ("text.move", + {"type": 'E', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'LINE_END'), + ], + }, + ), + ("text.move", + {"type": 'E', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'LINE_END'), + ], + }, + ), + ("text.move", + {"type": 'LEFT_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("text.move", + {"type": 'RIGHT_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_CHARACTER'), + ], + }, + ), + ("text.move", + {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("text.move", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("text.move", + {"type": 'UP_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_LINE'), + ], + }, + ), + ("text.move", + {"type": 'DOWN_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_LINE'), + ], + }, + ), + ("text.move", + {"type": 'PAGE_UP', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_PAGE'), + ], + }, + ), + ("text.move", + {"type": 'PAGE_DOWN', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_PAGE'), + ], + }, + ), + ("text.move", + {"type": 'HOME', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'FILE_TOP'), + ], + }, + ), + ("text.move", + {"type": 'END', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'FILE_BOTTOM'), + ], + }, + ), + ("text.move_select", + {"type": 'HOME', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'LINE_BEGIN'), + ], + }, + ), + ("text.move_select", + {"type": 'END', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'LINE_END'), + ], + }, + ), + ("text.move_select", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("text.move_select", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'NEXT_CHARACTER'), + ], + }, + ), + ("text.move_select", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("text.move_select", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("text.move_select", + {"type": 'UP_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_LINE'), + ], + }, + ), + ("text.move_select", + {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'NEXT_LINE'), + ], + }, + ), + ("text.move_select", + {"type": 'PAGE_UP', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_PAGE'), + ], + }, + ), + ("text.move_select", + {"type": 'PAGE_DOWN', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'NEXT_PAGE'), + ], + }, + ), + ("text.move_select", + {"type": 'HOME', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'FILE_TOP'), + ], + }, + ), + ("text.move_select", + {"type": 'END', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("type", 'FILE_BOTTOM'), + ], + }, + ), + ("text.delete", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_CHARACTER'), + ], + }, + ), + ("text.delete", + {"type": 'BACK_SPACE', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("text.delete", + {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("text.delete", + {"type": 'DEL', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("text.delete", + {"type": 'BACK_SPACE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("text.overwrite_toggle", {"type": 'INSERT', "value": 'PRESS'}, None), + ("text.scroll_bar", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("text.scroll_bar", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("text.scroll", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("text.scroll", {"type": 'TRACKPADPAN', "value": 'ANY'}, None), + ("text.selection_set", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None), + ("text.cursor_set", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("text.selection_set", + {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("select", True), + ], + }, + ), + ("text.scroll", + {"type": 'WHEELUPMOUSE', "value": 'PRESS'}, + {"properties": + [("lines", -1), + ], + }, + ), + ("text.scroll", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS'}, + {"properties": + [("lines", 1), + ], + }, + ), + ("text.line_break", {"type": 'RET', "value": 'PRESS'}, None), + ("text.line_break", {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, None), + ("wm.call_menu", + {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}, + {"properties": + [("name", 'TEXT_MT_toolbox'), + ], + }, + ), + ("text.autocomplete", {"type": 'SPACE', "value": 'PRESS', "ctrl": True}, None), + ("text.line_number", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None), + ("text.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None), + ], + }, + ), + ("SequencerCommon", + {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("sequencer.properties", {"type": 'N', "value": 'PRESS'}, None), + ("wm.context_toggle", + {"type": 'O', "value": 'PRESS', "shift": True}, + {"properties": + [("data_path", 'scene.sequence_editor.show_overlay'), + ], + }, + ), + ("sequencer.view_toggle", {"type": 'TAB', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Sequencer", + {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("sequencer.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("sequencer.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("sequencer.cut", + {"type": 'K', "value": 'PRESS'}, + {"properties": + [("type", 'SOFT'), + ], + }, + ), + ("sequencer.cut", + {"type": 'K', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'HARD'), + ], + }, + ), + ("sequencer.mute", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("sequencer.mute", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("sequencer.unmute", + {"type": 'H', "value": 'PRESS', "alt": True}, + {"properties": + [("unselected", False), + ], + }, + ), + ("sequencer.unmute", + {"type": 'H', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("sequencer.lock", {"type": 'L', "value": 'PRESS', "shift": True}, None), + ("sequencer.unlock", {"type": 'L', "value": 'PRESS', "shift": True, "alt": True}, None), + ("sequencer.reassign_inputs", {"type": 'R', "value": 'PRESS'}, None), + ("sequencer.reload", {"type": 'R', "value": 'PRESS', "alt": True}, None), + ("sequencer.reload", + {"type": 'R', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("adjust_length", True), + ], + }, + ), + ("sequencer.offset_clear", {"type": 'O', "value": 'PRESS', "alt": True}, None), + ("sequencer.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None), + ("sequencer.delete", {"type": 'X', "value": 'PRESS'}, None), + ("sequencer.delete", {"type": 'DEL', "value": 'PRESS'}, None), + ("sequencer.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.images_separate", {"type": 'Y', "value": 'PRESS'}, None), + ("sequencer.meta_toggle", {"type": 'TAB', "value": 'PRESS'}, None), + ("sequencer.meta_make", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.meta_separate", {"type": 'G', "value": 'PRESS', "alt": True}, None), + ("sequencer.view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("sequencer.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("sequencer.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("sequencer.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + ("sequencer.strip_jump", + {"type": 'PAGE_UP', "value": 'PRESS'}, + {"properties": + [("next", True), + ("center", False), + ], + }, + ), + ("sequencer.strip_jump", + {"type": 'PAGE_DOWN', "value": 'PRESS'}, + {"properties": + [("next", False), + ("center", False), + ], + }, + ), + ("sequencer.strip_jump", + {"type": 'PAGE_UP', "value": 'PRESS', "alt": True}, + {"properties": + [("next", True), + ("center", True), + ], + }, + ), + ("sequencer.strip_jump", + {"type": 'PAGE_DOWN', "value": 'PRESS', "alt": True}, + {"properties": + [("next", False), + ("center", True), + ], + }, + ), + ("sequencer.swap", + {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("side", 'LEFT'), + ], + }, + ), + ("sequencer.swap", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("side", 'RIGHT'), + ], + }, + ), + ("sequencer.gap_remove", + {"type": 'BACK_SPACE', "value": 'PRESS'}, + {"properties": + [("all", False), + ], + }, + ), + ("sequencer.gap_remove", + {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, + {"properties": + [("all", True), + ], + }, + ), + ("sequencer.gap_insert", {"type": 'EQUAL', "value": 'PRESS', "shift": True}, None), + ("sequencer.snap", {"type": 'S', "value": 'PRESS', "shift": True}, None), + ("sequencer.swap_inputs", {"type": 'S', "value": 'PRESS', "alt": True}, None), + ("sequencer.cut_multicam", + {"type": 'ONE', "value": 'PRESS'}, + {"properties": + [("camera", 1), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'TWO', "value": 'PRESS'}, + {"properties": + [("camera", 2), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'THREE', "value": 'PRESS'}, + {"properties": + [("camera", 3), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'FOUR', "value": 'PRESS'}, + {"properties": + [("camera", 4), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'FIVE', "value": 'PRESS'}, + {"properties": + [("camera", 5), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'SIX', "value": 'PRESS'}, + {"properties": + [("camera", 6), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'SEVEN', "value": 'PRESS'}, + {"properties": + [("camera", 7), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'EIGHT', "value": 'PRESS'}, + {"properties": + [("camera", 8), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'NINE', "value": 'PRESS'}, + {"properties": + [("camera", 9), + ], + }, + ), + ("sequencer.cut_multicam", + {"type": 'ZERO', "value": 'PRESS'}, + {"properties": + [("camera", 10), + ], + }, + ), + ("sequencer.select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ("linked_handle", False), + ("left_right", 'NONE'), + ("linked_time", False), + ], + }, + ), + ("sequencer.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ("linked_handle", False), + ("left_right", 'NONE'), + ("linked_time", False), + ], + }, + ), + ("sequencer.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": + [("extend", False), + ("linked_handle", True), + ("left_right", 'NONE'), + ("linked_time", False), + ], + }, + ), + ("sequencer.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("extend", True), + ("linked_handle", True), + ("left_right", 'NONE'), + ("linked_time", False), + ], + }, + ), + ("sequencer.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("extend", False), + ("linked_handle", False), + ("left_right", 'MOUSE'), + ("linked_time", True), + ], + }, + ), + ("sequencer.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("extend", True), + ("linked_handle", False), + ("left_right", 'NONE'), + ("linked_time", True), + ], + }, + ), + ("sequencer.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.select_linked_pick", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("sequencer.select_linked_pick", + {"type": 'L', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("sequencer.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("sequencer.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None), + ("wm.call_menu", + {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'SEQUENCER_MT_add'), + ], + }, + ), + ("wm.call_menu", + {"type": 'C', "value": 'PRESS'}, + {"properties": + [("name", 'SEQUENCER_MT_change'), + ], + }, + ), + ("sequencer.slip", {"type": 'S', "value": 'PRESS'}, None), + ("wm.context_set_int", + {"type": 'O', "value": 'PRESS'}, + {"properties": + [("data_path", 'scene.sequence_editor.overlay_frame'), + ("value", 0), + ], + }, + ), + ("transform.seq_slide", {"type": 'G', "value": 'PRESS'}, None), + ("transform.seq_slide", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.transform", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("mode", 'TIME_EXTEND'), + ], + }, + ), + ("marker.add", {"type": 'M', "value": 'PRESS'}, None), + ("marker.rename", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("SequencerPreview", + {"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("sequencer.view_all_preview", {"type": 'HOME', "value": 'PRESS'}, None), + ("sequencer.view_all_preview", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("sequencer.view_ghost_border", {"type": 'O', "value": 'PRESS'}, None), + ("sequencer.view_zoom_ratio", + {"type": 'NUMPAD_1', "value": 'PRESS'}, + {"properties": + [("ratio", 1.0), + ], + }, + ), + ("sequencer.sample", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ], + }, + ), + ("Console", + {"space_type": 'CONSOLE', "region_type": 'WINDOW'}, + {"items": + [("console.move", + {"type": 'LEFT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("console.move", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("console.move", + {"type": 'HOME', "value": 'PRESS'}, + {"properties": + [("type", 'LINE_BEGIN'), + ], + }, + ), + ("console.move", + {"type": 'END', "value": 'PRESS'}, + {"properties": + [("type", 'LINE_END'), + ], + }, + ), + ("wm.context_cycle_int", + {"type": 'WHEELUPMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", False), + ], + }, + ), + ("wm.context_cycle_int", + {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", True), + ], + }, + ), + ("wm.context_cycle_int", + {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", False), + ], + }, + ), + ("wm.context_cycle_int", + {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.font_size'), + ("reverse", True), + ], + }, + ), + ("console.move", + {"type": 'LEFT_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("console.move", + {"type": 'RIGHT_ARROW', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_CHARACTER'), + ], + }, + ), + ("console.history_cycle", + {"type": 'UP_ARROW', "value": 'PRESS'}, + {"properties": + [("reverse", True), + ], + }, + ), + ("console.history_cycle", + {"type": 'DOWN_ARROW', "value": 'PRESS'}, + {"properties": + [("reverse", False), + ], + }, + ), + ("console.delete", + {"type": 'DEL', "value": 'PRESS'}, + {"properties": + [("type", 'NEXT_CHARACTER'), + ], + }, + ), + ("console.delete", + {"type": 'BACK_SPACE', "value": 'PRESS'}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("console.delete", + {"type": 'BACK_SPACE', "value": 'PRESS', "shift": True}, + {"properties": + [("type", 'PREVIOUS_CHARACTER'), + ], + }, + ), + ("console.delete", + {"type": 'DEL', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'NEXT_WORD'), + ], + }, + ), + ("console.delete", + {"type": 'BACK_SPACE', "value": 'PRESS', "ctrl": True}, + {"properties": + [("type", 'PREVIOUS_WORD'), + ], + }, + ), + ("console.clear_line", {"type": 'RET', "value": 'PRESS', "shift": True}, None), + ("console.clear_line", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "shift": True}, None), + ("console.execute", + {"type": 'RET', "value": 'PRESS'}, + {"properties": + [("interactive", True), + ], + }, + ), + ("console.execute", + {"type": 'NUMPAD_ENTER', "value": 'PRESS'}, + {"properties": + [("interactive", True), + ], + }, + ), + ("console.autocomplete", {"type": 'SPACE', "value": 'PRESS', "ctrl": True}, None), + ("console.copy_as_script", {"type": 'C', "value": 'PRESS', "shift": True, "ctrl": True}, None), + ("console.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("console.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("console.select_set", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("console.select_word", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None), + ("console.insert", + {"type": 'TAB', "value": 'PRESS', "ctrl": True}, + {"properties": + [("text", '\t'), + ], + }, + ), + ("console.indent", {"type": 'TAB', "value": 'PRESS'}, None), + ("console.unindent", {"type": 'TAB', "value": 'PRESS', "shift": True}, None), + ("console.insert", {"type": 'TEXTINPUT', "value": 'ANY', "any": True}, None), + ], + }, + ), + ("Clip", + {"space_type": 'CLIP_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("clip.open", {"type": 'O', "value": 'PRESS', "alt": True}, None), + ("clip.tools", {"type": 'T', "value": 'PRESS'}, None), + ("clip.properties", {"type": 'N', "value": 'PRESS'}, None), + ("clip.track_markers", + {"type": 'LEFT_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("backwards", True), + ("sequence", False), + ], + }, + ), + ("clip.track_markers", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "alt": True}, + {"properties": + [("backwards", False), + ("sequence", False), + ], + }, + ), + ("clip.track_markers", + {"type": 'T', "value": 'PRESS', "ctrl": True}, + {"properties": + [("backwards", False), + ("sequence", True), + ], + }, + ), + ("clip.track_markers", + {"type": 'T', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("backwards", True), + ("sequence", True), + ], + }, + ), + ("wm.context_toggle_enum", + {"type": 'TAB', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.mode'), + ("value_1", 'TRACKING'), + ("value_2", 'MASK'), + ], + }, + ), + ("clip.solve_camera", {"type": 'S', "value": 'PRESS', "shift": True}, None), + ("clip.set_solver_keyframe", + {"type": 'Q', "value": 'PRESS'}, + {"properties": + [("keyframe", 'KEYFRAME_A'), + ], + }, + ), + ("clip.set_solver_keyframe", + {"type": 'E', "value": 'PRESS'}, + {"properties": + [("keyframe", 'KEYFRAME_B'), + ], + }, + ), + ("clip.prefetch", {"type": 'P', "value": 'PRESS'}, None), + ], + }, + ), + ("Clip Editor", + {"space_type": 'CLIP_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("clip.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None), + ("clip.view_pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None), + ("clip.view_pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None), + ("clip.view_zoom", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("clip.view_zoom", {"type": 'TRACKPADZOOM', "value": 'ANY'}, None), + ("clip.view_zoom", {"type": 'TRACKPADPAN', "value": 'ANY', "ctrl": True}, None), + ("clip.view_zoom_in", {"type": 'WHEELINMOUSE', "value": 'PRESS'}, None), + ("clip.view_zoom_out", {"type": 'WHEELOUTMOUSE', "value": 'PRESS'}, None), + ("clip.view_zoom_in", {"type": 'NUMPAD_PLUS', "value": 'PRESS'}, None), + ("clip.view_zoom_out", {"type": 'NUMPAD_MINUS', "value": 'PRESS'}, None), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_8', "value": 'PRESS', "ctrl": True}, + {"properties": + [("ratio", 8.0), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_4', "value": 'PRESS', "ctrl": True}, + {"properties": + [("ratio", 4.0), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_2', "value": 'PRESS', "ctrl": True}, + {"properties": + [("ratio", 2.0), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_8', "value": 'PRESS', "shift": True}, + {"properties": + [("ratio", 8.0), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_4', "value": 'PRESS', "shift": True}, + {"properties": + [("ratio", 4.0), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_2', "value": 'PRESS', "shift": True}, + {"properties": + [("ratio", 2.0), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_1', "value": 'PRESS'}, + {"properties": + [("ratio", 1.0), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_2', "value": 'PRESS'}, + {"properties": + [("ratio", 0.5), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_4', "value": 'PRESS'}, + {"properties": + [("ratio", 0.25), + ], + }, + ), + ("clip.view_zoom_ratio", + {"type": 'NUMPAD_8', "value": 'PRESS'}, + {"properties": + [("ratio", 0.125), + ], + }, + ), + ("clip.view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("clip.view_all", + {"type": 'F', "value": 'PRESS'}, + {"properties": + [("fit_view", True), + ], + }, + ), + ("clip.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("clip.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("clip.view_ndof", {"type": 'NDOF_MOTION', "value": 'ANY'}, None), + ("clip.frame_jump", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("position", 'PATHSTART'), + ], + }, + ), + ("clip.frame_jump", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True, "ctrl": True}, + {"properties": + [("position", 'PATHEND'), + ], + }, + ), + ("clip.frame_jump", + {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("position", 'FAILEDPREV'), + ], + }, + ), + ("clip.frame_jump", + {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("position", 'PATHSTART'), + ], + }, + ), + ("clip.change_frame", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("clip.select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("clip.select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("clip.select_all", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("clip.select_all", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("clip.select_border", {"type": 'B', "value": 'PRESS'}, None), + ("clip.select_circle", {"type": 'C', "value": 'PRESS'}, None), + ("wm.call_menu", + {"type": 'G', "value": 'PRESS', "shift": True}, + {"properties": + [("name", 'CLIP_MT_select_grouped'), + ], + }, + ), + ("clip.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "ctrl": True, "alt": True}, + {"properties": + [("deselect", False), + ], + }, + ), + ("clip.select_lasso", + {"type": 'EVT_TWEAK_A', "value": 'ANY', "shift": True, "ctrl": True, "alt": True}, + {"properties": + [("deselect", True), + ], + }, + ), + ("clip.add_marker_slide", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None), + ("clip.delete_marker", {"type": 'DEL', "value": 'PRESS', "shift": True}, None), + ("clip.delete_marker", {"type": 'X', "value": 'PRESS', "shift": True}, None), + ("clip.slide_marker", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), + ("clip.disable_markers", + {"type": 'D', "value": 'PRESS', "shift": True}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("clip.delete_track", {"type": 'DEL', "value": 'PRESS'}, None), + ("clip.delete_track", {"type": 'X', "value": 'PRESS'}, None), + ("clip.lock_tracks", + {"type": 'L', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'LOCK'), + ], + }, + ), + ("clip.lock_tracks", + {"type": 'L', "value": 'PRESS', "alt": True}, + {"properties": + [("action", 'UNLOCK'), + ], + }, + ), + ("clip.hide_tracks", + {"type": 'H', "value": 'PRESS'}, + {"properties": + [("unselected", False), + ], + }, + ), + ("clip.hide_tracks", + {"type": 'H', "value": 'PRESS', "shift": True}, + {"properties": + [("unselected", True), + ], + }, + ), + ("clip.hide_tracks_clear", {"type": 'H', "value": 'PRESS', "alt": True}, None), + ("clip.slide_plane_marker", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("clip.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None), + ("clip.keyframe_delete", {"type": 'I', "value": 'PRESS', "alt": True}, None), + ("clip.join_tracks", {"type": 'J', "value": 'PRESS', "ctrl": True}, None), + ("wm.call_menu", + {"type": 'W', "value": 'PRESS'}, + {"properties": + [("name", 'CLIP_MT_tracking_specials'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.lock_selection'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'D', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'space_data.show_disabled'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'S', "value": 'PRESS', "alt": True}, + {"properties": + [("data_path", 'space_data.show_marker_search'), + ], + }, + ), + ("wm.context_toggle", + {"type": 'M', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.use_mute_footage'), + ], + }, + ), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ("clip.clear_track_path", + {"type": 'T', "value": 'PRESS', "alt": True}, + {"properties": + [("action", 'REMAINED'), + ("clear_active", False), + ], + }, + ), + ("clip.clear_track_path", + {"type": 'T', "value": 'PRESS', "shift": True}, + {"properties": + [("action", 'UPTO'), + ("clear_active", False), + ], + }, + ), + ("clip.clear_track_path", + {"type": 'T', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("action", 'ALL'), + ("clear_active", False), + ], + }, + ), + ("clip.cursor_set", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("wm.context_set_enum", + {"type": 'COMMA', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'BOUNDING_BOX_CENTER'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'COMMA', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'MEDIAN_POINT'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'CURSOR'), + ], + }, + ), + ("wm.context_set_enum", + {"type": 'PERIOD', "value": 'PRESS', "ctrl": True}, + {"properties": + [("data_path", 'space_data.pivot_point'), + ("value", 'INDIVIDUAL_ORIGINS'), + ], + }, + ), + ("clip.copy_tracks", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), + ("clip.paste_tracks", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ], + }, + ), + ("Clip Graph Editor", + {"space_type": 'CLIP_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("clip.change_frame", {"type": 'ACTIONMOUSE', "value": 'PRESS'}, None), + ("clip.graph_select", + {"type": 'SELECTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", False), + ], + }, + ), + ("clip.graph_select", + {"type": 'SELECTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": + [("extend", True), + ], + }, + ), + ("clip.graph_select_all_markers", + {"type": 'A', "value": 'PRESS'}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("clip.graph_select_all_markers", + {"type": 'I', "value": 'PRESS', "ctrl": True}, + {"properties": + [("action", 'INVERT'), + ], + }, + ), + ("clip.graph_select_border", {"type": 'B', "value": 'PRESS'}, None), + ("clip.graph_delete_curve", {"type": 'DEL', "value": 'PRESS'}, None), + ("clip.graph_delete_curve", {"type": 'X', "value": 'PRESS'}, None), + ("clip.graph_delete_knot", {"type": 'DEL', "value": 'PRESS', "shift": True}, None), + ("clip.graph_delete_knot", {"type": 'X', "value": 'PRESS', "shift": True}, None), + ("clip.graph_view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("clip.graph_view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ("clip.graph_center_current_frame", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + ("wm.context_toggle", + {"type": 'L', "value": 'PRESS'}, + {"properties": + [("data_path", 'space_data.lock_time_cursor'), + ], + }, + ), + ("clip.clear_track_path", + {"type": 'T', "value": 'PRESS', "alt": True}, + {"properties": + [("action", 'REMAINED'), + ("clear_active", True), + ], + }, + ), + ("clip.clear_track_path", + {"type": 'T', "value": 'PRESS', "shift": True}, + {"properties": + [("action", 'UPTO'), + ("clear_active", True), + ], + }, + ), + ("clip.clear_track_path", + {"type": 'T', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": + [("action", 'ALL'), + ("clear_active", True), + ], + }, + ), + ("clip.graph_disable_markers", + {"type": 'D', "value": 'PRESS', "shift": True}, + {"properties": + [("action", 'TOGGLE'), + ], + }, + ), + ("transform.translate", {"type": 'G', "value": 'PRESS'}, None), + ("transform.translate", {"type": 'EVT_TWEAK_S', "value": 'ANY'}, None), + ("transform.resize", {"type": 'S', "value": 'PRESS'}, None), + ("transform.rotate", {"type": 'R', "value": 'PRESS'}, None), + ], + }, + ), + ("Clip Dopesheet Editor", + {"space_type": 'CLIP_EDITOR', "region_type": 'WINDOW'}, + {"items": + [("clip.dopesheet_select_channel", + {"type": 'LEFTMOUSE', "value": 'PRESS'}, + {"properties": + [("extend", True), + ], + }, + ), + ("clip.dopesheet_view_all", {"type": 'HOME', "value": 'PRESS'}, None), + ("clip.dopesheet_view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), + ], + }, + ), + ("3D View Tool: OBJECT, Move", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("transform.translate", + {"type": 'EVT_TWEAK_A', "value": 'ANY'}, + {"properties": + [("release_confirm", True), + ], + }, + ), + ], + }, + ), + ("3D View Tool: OBJECT, Rotate", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("transform.rotate", + {"type": 'EVT_TWEAK_A', "value": 'ANY'}, + {"properties": + [("release_confirm", True), + ], + }, + ), + ], + }, + ), + ("3D View Tool: OBJECT, Scale", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("transform.resize", + {"type": 'EVT_TWEAK_A', "value": 'ANY'}, + {"properties": + [("release_confirm", True), + ], + }, + ), + ], + }, + ), + ("3D View Tool: OBJECT, Ruler/Protractor", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("view3d.ruler_add", {"type": 'EVT_TWEAK_A', "value": 'ANY'}, None), + ], + }, + ), + ("3D View Tool: PARTICLE, Cursor Click", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("view3d.cursor3d", {"type": 'ACTIONMOUSE', "value": 'CLICK'}, None), + ], + }, + ), + ("Spot Lamp Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Area Lamp Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ("Target Lamp Widgets", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": + [("manipulatorgroup.manipulator_tweak", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ], + }, + ), + ] + + +if __name__ == "__main__": + import os + from bpy_extras.keyconfig_utils import keyconfig_import_from_data + keyconfig_import_from_data(os.path.splitext(os.path.basename(__file__))[0], keyconfig_data) diff --git a/release/scripts/presets/keyconfig/maya.py b/release/scripts/presets/keyconfig/maya.py index 855f8d928cd..da1446f6f43 100644 --- a/release/scripts/presets/keyconfig/maya.py +++ b/release/scripts/presets/keyconfig/maya.py @@ -8,7 +8,7 @@ kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0]) # Map Window km = kc.keymaps.new('Window', space_type='EMPTY', region_type='WINDOW', modal=False) -kmi = km.keymap_items.new('wm.window_duplicate', 'W', 'PRESS', ctrl=True, alt=True) +kmi = km.keymap_items.new('wm.window_new', 'W', 'PRESS', ctrl=True, alt=True) kmi = km.keymap_items.new('wm.read_homefile', 'N', 'PRESS', ctrl=True) kmi = km.keymap_items.new('wm.save_homefile', 'U', 'PRESS', ctrl=True) kmi = km.keymap_items.new('wm.call_menu', 'O', 'PRESS', shift=True, ctrl=True) @@ -33,9 +33,6 @@ kmi = km.keymap_items.new('wm.call_menu', 'NDOF_BUTTON_MENU', 'PRESS') kmi.properties.name = 'USERPREF_MT_ndof_settings' kmi = km.keymap_items.new('wm.context_set_enum', 'F2', 'PRESS', shift=True) kmi.properties.data_path = 'area.type' -kmi.properties.value = 'LOGIC_EDITOR' -kmi = km.keymap_items.new('wm.context_set_enum', 'F3', 'PRESS', shift=True) -kmi.properties.data_path = 'area.type' kmi.properties.value = 'NODE_EDITOR' kmi = km.keymap_items.new('wm.context_set_enum', 'F4', 'PRESS', shift=True) kmi.properties.data_path = 'area.type' @@ -383,7 +380,6 @@ kmi = km.keymap_items.new('object.hide_view_clear', 'H', 'PRESS', shift=True, ct kmi = km.keymap_items.new('object.hide_view_set', 'H', 'PRESS', ctrl=True) kmi = km.keymap_items.new('object.hide_view_set', 'H', 'PRESS', alt=True) kmi.properties.unselected = True -kmi = km.keymap_items.new('object.move_to_layer', 'M', 'PRESS') kmi = km.keymap_items.new('object.delete', 'BACK_SPACE', 'PRESS') kmi = km.keymap_items.new('object.delete', 'DEL', 'PRESS') kmi = km.keymap_items.new('wm.call_menu', 'A', 'PRESS', shift=True) @@ -773,17 +769,6 @@ kmi.properties.value_2 = 'CONNECTED' # Map Armature km = kc.keymaps.new('Armature', space_type='EMPTY', region_type='WINDOW', modal=False) -kmi = km.keymap_items.new('sketch.delete', 'BACK_SPACE', 'PRESS') -kmi = km.keymap_items.new('sketch.delete', 'DEL', 'PRESS') -kmi = km.keymap_items.new('sketch.finish_stroke', 'RIGHTMOUSE', 'PRESS') -kmi = km.keymap_items.new('sketch.cancel_stroke', 'ESC', 'PRESS') -kmi = km.keymap_items.new('sketch.gesture', 'LEFTMOUSE', 'PRESS', shift=True) -kmi = km.keymap_items.new('sketch.draw_stroke', 'LEFTMOUSE', 'PRESS') -kmi = km.keymap_items.new('sketch.draw_stroke', 'LEFTMOUSE', 'PRESS', ctrl=True) -kmi.properties.snap = True -kmi = km.keymap_items.new('sketch.draw_preview', 'MOUSEMOVE', 'ANY') -kmi = km.keymap_items.new('sketch.draw_preview', 'MOUSEMOVE', 'ANY', ctrl=True) -kmi.properties.snap = True kmi = km.keymap_items.new('armature.hide', 'H', 'PRESS', ctrl=True) kmi.properties.unselected = False kmi = km.keymap_items.new('armature.hide', 'H', 'PRESS', alt=True) @@ -1001,11 +986,11 @@ kmi = km.keymap_items.new('view3d.view_orbit', 'WHEELDOWNMOUSE', 'PRESS', shift= kmi.properties.type = 'ORBITDOWN' kmi = km.keymap_items.new('view3d.localview', 'I', 'PRESS', shift=True) kmi = km.keymap_items.new('wm.context_toggle_enum', 'FOUR', 'PRESS') -kmi.properties.data_path = 'space_data.viewport_shade' +kmi.properties.data_path = 'space_data.shading.type' kmi.properties.value_1 = 'WIREFRAME' kmi.properties.value_2 = 'WIREFRAME' kmi = km.keymap_items.new('wm.context_toggle_enum', 'FIVE', 'PRESS') -kmi.properties.data_path = 'space_data.viewport_shade' +kmi.properties.data_path = 'space_data.shading.type' kmi.properties.value_1 = 'TEXTURED' kmi.properties.value_2 = 'SOLID' kmi = km.keymap_items.new('view3d.select_or_deselect_all', 'SELECTMOUSE', 'CLICK') @@ -1094,7 +1079,7 @@ kmi.properties.rotate = True kmi = km.keymap_items.new('view3d.enable_manipulator', 'R', 'PRESS') kmi.properties.scale = True kmi = km.keymap_items.new('wm.context_toggle_enum', 'SIX', 'PRESS') -kmi.properties.data_path = 'space_data.viewport_shade' +kmi.properties.data_path = 'space_data.shading.type' kmi.properties.value_1 = 'TEXTURED' kmi.properties.value_2 = 'TEXTURED' kmi = km.keymap_items.new('wm.context_set_enum', 'X', 'PRESS') @@ -1499,7 +1484,7 @@ kmi.properties.prev = False kmi = km.keymap_items.new('node.group_make', 'G', 'PRESS', ctrl=True) kmi = km.keymap_items.new('node.group_ungroup', 'G', 'PRESS', alt=True) kmi = km.keymap_items.new('node.group_edit', 'TAB', 'PRESS') -kmi = km.keymap_items.new('node.read_renderlayers', 'R', 'PRESS', ctrl=True) +kmi = km.keymap_items.new('node.read_viewlayers', 'R', 'PRESS', ctrl=True) kmi = km.keymap_items.new('node.read_fullsamplelayers', 'R', 'PRESS', shift=True) kmi = km.keymap_items.new('node.render_changed', 'Z', 'PRESS') kmi = km.keymap_items.new('node.translate_attach', 'W', 'PRESS') diff --git a/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_rigged.py b/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_rigged.py index deb23d76d91..7825a4d0f32 100644 --- a/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_rigged.py +++ b/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_rigged.py @@ -10,7 +10,7 @@ op.include_armatures = True op.include_shapekeys = False op.deform_bones_only = True op.active_uv_only = True -op.export_texture_type_selection = 'uv' +op.include_uv_textures = True op.use_texture_copies = True op.triangulate = True op.use_object_instantiation = False diff --git a/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_static.py b/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_static.py index ca9de8bf005..a13ba5c4ccc 100644 --- a/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_static.py +++ b/release/scripts/presets/operator/wm.collada_export/sl_plus_open_sim_static.py @@ -10,7 +10,6 @@ op.include_armatures = False op.include_shapekeys = False op.deform_bones_only = False op.active_uv_only = True -op.export_texture_type_selection = 'uv' op.use_texture_copies = True op.triangulate = True op.use_object_instantiation = False diff --git a/release/scripts/presets/sunsky/classic.py b/release/scripts/presets/sunsky/classic.py deleted file mode 100644 index edb065d553c..00000000000 --- a/release/scripts/presets/sunsky/classic.py +++ /dev/null @@ -1,14 +0,0 @@ -import bpy -bpy.context.lamp.sky.atmosphere_turbidity = 4.0 -bpy.context.lamp.sky.sky_blend_type = 'ADD' -bpy.context.lamp.sky.sky_blend = 1.0 -bpy.context.lamp.sky.horizon_brightness = 10.0 -bpy.context.lamp.sky.spread = 1.49011614159e-09 -bpy.context.lamp.sky.sky_color_space = 'SMPTE' -bpy.context.lamp.sky.sky_exposure = 1.0 -bpy.context.lamp.sky.sun_brightness = 1.00000011921 -bpy.context.lamp.sky.sun_size = 1.00000166893 -bpy.context.lamp.sky.backscattered_light = 0.0 -bpy.context.lamp.sky.sun_intensity = 4.0 -bpy.context.lamp.sky.atmosphere_inscattering = 1.0 -bpy.context.lamp.sky.atmosphere_extinction = 1.0 diff --git a/release/scripts/presets/sunsky/desert.py b/release/scripts/presets/sunsky/desert.py deleted file mode 100644 index 8dd587a6eaf..00000000000 --- a/release/scripts/presets/sunsky/desert.py +++ /dev/null @@ -1,14 +0,0 @@ -import bpy -bpy.context.lamp.sky.atmosphere_turbidity = 6.0 -bpy.context.lamp.sky.sky_blend_type = 'ADD' -bpy.context.lamp.sky.sky_blend = 1.0 -bpy.context.lamp.sky.horizon_brightness = 4.99999761581 -bpy.context.lamp.sky.spread = 1.49011614159e-09 -bpy.context.lamp.sky.sky_color_space = 'SMPTE' -bpy.context.lamp.sky.sky_exposure = 1.0 -bpy.context.lamp.sky.sun_brightness = 1.00000011921 -bpy.context.lamp.sky.sun_size = 4.0 -bpy.context.lamp.sky.backscattered_light = 1.0 -bpy.context.lamp.sky.sun_intensity = 1.0 -bpy.context.lamp.sky.atmosphere_inscattering = 1.0 -bpy.context.lamp.sky.atmosphere_extinction = 1.0 diff --git a/release/scripts/presets/sunsky/mountain.py b/release/scripts/presets/sunsky/mountain.py deleted file mode 100644 index f0540af8100..00000000000 --- a/release/scripts/presets/sunsky/mountain.py +++ /dev/null @@ -1,14 +0,0 @@ -import bpy -bpy.context.lamp.sky.atmosphere_turbidity = 2.00000023842 -bpy.context.lamp.sky.sky_blend_type = 'ADD' -bpy.context.lamp.sky.sky_blend = 1.0 -bpy.context.lamp.sky.horizon_brightness = 0.100000016391 -bpy.context.lamp.sky.spread = 1.0 -bpy.context.lamp.sky.sky_color_space = 'SMPTE' -bpy.context.lamp.sky.sky_exposure = 1.0 -bpy.context.lamp.sky.sun_brightness = 1.99999988079 -bpy.context.lamp.sky.sun_size = 4.0 -bpy.context.lamp.sky.backscattered_light = -1.0 -bpy.context.lamp.sky.sun_intensity = 10.0 -bpy.context.lamp.sky.atmosphere_inscattering = 1.0 -bpy.context.lamp.sky.atmosphere_extinction = 1.0 diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 4af600473d1..4460af173ff 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -79,7 +79,7 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): def add_uvs(mesh, minor_seg, major_seg): from math import fmod - mesh.uv_textures.new() + mesh.uv_layers.new() uv_data = mesh.uv_layers.active.data polygons = mesh.polygons u_step = 1.0 / major_seg @@ -134,19 +134,19 @@ class AddTorus(Operator, object_utils.AddObjectHelper): self.abso_major_rad = self.major_radius + self.minor_radius self.abso_minor_rad = self.major_radius - self.minor_radius - major_segments = IntProperty( + major_segments: IntProperty( name="Major Segments", description="Number of segments for the main ring of the torus", min=3, max=256, default=48, ) - minor_segments = IntProperty( + minor_segments: IntProperty( name="Minor Segments", description="Number of segments for the minor ring of the torus", min=3, max=256, default=12, ) - mode = bpy.props.EnumProperty( + mode: bpy.props.EnumProperty( name="Torus Dimensions", items=(("MAJOR_MINOR", "Major/Minor", "Use the major/minor radii for torus dimensions"), @@ -154,7 +154,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper): "Use the exterior/interior radii for torus dimensions")), update=mode_update_callback, ) - major_radius = FloatProperty( + major_radius: FloatProperty( name="Major Radius", description=("Radius from the origin to the " "center of the cross sections"), @@ -163,7 +163,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper): subtype='DISTANCE', unit='LENGTH', ) - minor_radius = FloatProperty( + minor_radius: FloatProperty( name="Minor Radius", description="Radius of the torus' cross section", min=0.01, max=100.0, @@ -171,7 +171,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper): subtype='DISTANCE', unit='LENGTH', ) - abso_major_rad = FloatProperty( + abso_major_rad: FloatProperty( name="Exterior Radius", description="Total Exterior Radius of the torus", min=0.01, max=100.0, @@ -179,7 +179,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper): subtype='DISTANCE', unit='LENGTH', ) - abso_minor_rad = FloatProperty( + abso_minor_rad: FloatProperty( name="Interior Radius", description="Total Interior Radius of the torus", min=0.01, max=100.0, @@ -187,7 +187,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper): subtype='DISTANCE', unit='LENGTH', ) - generate_uvs = BoolProperty( + generate_uvs: BoolProperty( name="Generate UVs", description="Generate a default UV map", default=False, diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index 250c88b9009..31325cf0b50 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -40,20 +40,20 @@ class ANIM_OT_keying_set_export(Operator): bl_idname = "anim.keying_set_export" bl_label = "Export Keying Set..." - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) - filter_text = BoolProperty( + filter_text: BoolProperty( name="Filter text", default=True, options={'HIDDEN'}, ) - filter_python = BoolProperty( + filter_python: BoolProperty( name="Filter python", default=True, options={'HIDDEN'}, @@ -110,7 +110,7 @@ class ANIM_OT_keying_set_export(Operator): # - special handling is needed for "nested" ID-blocks # (e.g. nodetree in Material) if ksp.id.bl_rna.identifier.startswith("ShaderNodeTree"): - # Find material or lamp using this node tree... + # Find material or light using this node tree... id_bpy_path = "bpy.data.nodes[\"%s\"]" found = False @@ -121,14 +121,14 @@ class ANIM_OT_keying_set_export(Operator): break if not found: - for lamp in bpy.data.lamps: - if lamp.node_tree == ksp.id: - id_bpy_path = "bpy.data.lamps[\"%s\"].node_tree" % (lamp.name) + for light in bpy.data.lights: + if light.node_tree == ksp.id: + id_bpy_path = "bpy.data.lights[\"%s\"].node_tree" % (light.name) found = True break if not found: - self.report({'WARN'}, "Could not find material or lamp using Shader Node Tree - %s" % (ksp.id)) + self.report({'WARN'}, "Could not find material or light using Shader Node Tree - %s" % (ksp.id)) elif ksp.id.bl_rna.identifier.startswith("CompositorNodeTree"): # Find compositor nodetree using this node tree... for scene in bpy.data.scenes: @@ -203,51 +203,51 @@ class BakeAction(Operator): bl_label = "Bake Action" bl_options = {'REGISTER', 'UNDO'} - frame_start = IntProperty( + frame_start: IntProperty( name="Start Frame", description="Start frame for baking", min=0, max=300000, default=1, ) - frame_end = IntProperty( + frame_end: IntProperty( name="End Frame", description="End frame for baking", min=1, max=300000, default=250, ) - step = IntProperty( + step: IntProperty( name="Frame Step", description="Frame Step", min=1, max=120, default=1, ) - only_selected = BoolProperty( + only_selected: BoolProperty( name="Only Selected Bones", description="Only key selected bones (Pose baking only)", default=True, ) - visual_keying = BoolProperty( + visual_keying: BoolProperty( name="Visual Keying", description="Keyframe from the final transformations (with constraints applied)", default=False, ) - clear_constraints = BoolProperty( + clear_constraints: BoolProperty( name="Clear Constraints", description="Remove all constraints from keyed object/bones, and do 'visual' keying", default=False, ) - clear_parents = BoolProperty( + clear_parents: BoolProperty( name="Clear Parents", description="Bake animation onto the object then clear parents (objects only)", default=False, ) - use_current_action = BoolProperty( + use_current_action: BoolProperty( name="Overwrite Current Action", description="Bake animation into current action, instead of creating a new one " "(useful for baking only part of bones in an armature)", default=False, ) - bake_types = EnumProperty( + bake_types: EnumProperty( name="Bake Data", description="Which data's transformations to bake", options={'ENUM_FLAG'}, @@ -302,7 +302,7 @@ class ClearUselessActions(Operator): bl_label = "Clear Useless Actions" bl_options = {'REGISTER', 'UNDO'} - only_unused = BoolProperty( + only_unused: BoolProperty( name="Only Unused", description="Only unused (Fake User only) actions get considered", default=True, @@ -341,7 +341,7 @@ class UpdateAnimatedTransformConstraint(Operator): bl_label = "Update Animated Transform Constraints" bl_options = {'REGISTER', 'UNDO'} - use_convert_to_radians = BoolProperty( + use_convert_to_radians: BoolProperty( name="Convert To Radians", description="Convert fcurves/drivers affecting rotations to radians (Warning: use this only once!)", default=True, diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py index dda6b2fa5ab..a94076ab61b 100644 --- a/release/scripts/startup/bl_operators/clip.py +++ b/release/scripts/startup/bl_operators/clip.py @@ -133,7 +133,7 @@ class CLIP_OT_filter_tracks(bpy.types.Operator): bl_idname = "clip.filter_tracks" bl_options = {'UNDO', 'REGISTER'} - track_threshold = FloatProperty( + track_threshold: FloatProperty( name="Track Threshold", description="Filter Threshold to select problematic tracks", default=5.0, @@ -236,9 +236,9 @@ class CLIP_OT_track_to_empty(Operator): ob = None ob = bpy.data.objects.new(name=track.name, object_data=None) - ob.select = True + ob.select_set(action='SELECT') context.scene.objects.link(ob) - context.scene.objects.active = ob + context.view_layer.objects.active = ob for con in ob.constraints: if con.type == 'FOLLOW_TRACK': @@ -314,7 +314,7 @@ class CLIP_OT_bundles_to_mesh(Operator): ob.matrix_world = matrix context.scene.objects.link(ob) ob.select = True - context.scene.objects.active = ob + context.view_layer.objects.active = ob else: self.report({'WARNING'}, "No usable tracks selected") @@ -516,7 +516,7 @@ object's movement caused by this constraint""" # XXX, should probably use context.selected_editable_objects # since selected objects can be from a lib or in hidden layer! for ob in scene.objects: - if ob.select: + if ob.select_set(action='SELECT'): self._bake_object(scene, ob) return {'FINISHED'} @@ -613,24 +613,24 @@ class CLIP_OT_setup_tracking_scene(Operator): CLIP_set_viewport_background(context, True, sc.clip, sc.clip_user) @staticmethod - def _setupRenderLayers(context): + def _setupViewLayers(context): scene = context.scene - rlayers = scene.render.layers + view_layers = scene.view_layers - if not scene.render.layers.get("Foreground"): - if len(rlayers) == 1: - fg = rlayers[0] + if not view_layers.get("Foreground"): + if len(view_layers) == 1: + fg = view_layers[0] fg.name = 'Foreground' else: - fg = scene.render.layers.new("Foreground") + fg = view_layers.new("Foreground") fg.use_sky = True fg.layers = [True] + [False] * 19 fg.layers_zmask = [False] * 10 + [True] + [False] * 9 fg.use_pass_vector = True - if not scene.render.layers.get("Background"): - bg = scene.render.layers.new("Background") + if not view_layers.get("Background"): + bg = view_layers.new("Background") bg.use_pass_shadow = True bg.use_pass_ambient_occlusion = True bg.layers = [False] * 10 + [True] + [False] * 9 @@ -915,17 +915,17 @@ class CLIP_OT_setup_tracking_scene(Operator): return [(layers_a[i] | layers_b[i]) for i in range(len(layers_a))] @staticmethod - def _createLamp(scene): - lamp = bpy.data.lamps.new(name="Lamp", type='POINT') - lampob = bpy.data.objects.new(name="Lamp", object_data=lamp) - scene.objects.link(lampob) + def _createLight(scene): + light = bpy.data.lights.new(name="Light", type='POINT') + lightob = bpy.data.objects.new(name="Light", object_data=light) + scene.objects.link(lightob) - lampob.matrix_local = Matrix.Translation((4.076, 1.005, 5.904)) + lightob.matrix_local = Matrix.Translation((4.076, 1.005, 5.904)) - lamp.distance = 30 - lamp.shadow_method = 'RAY_SHADOW' + light.distance = 30 + light.shadow_method = 'RAY_SHADOW' - return lampob + return lightob def _createSampleObject(self, scene): vertices = self._getPlaneVertices(1.0, -1.0) + \ @@ -942,25 +942,25 @@ class CLIP_OT_setup_tracking_scene(Operator): def _setupObjects(self, context): scene = context.scene - fg = scene.render.layers.get("Foreground") - bg = scene.render.layers.get("Background") + fg = scene.view_layers.get("Foreground") + bg = scene.view_layers.get("Background") all_layers = self._mergeLayers(fg.layers, bg.layers) - # ensure all lamps are active on foreground and background - has_lamp = False + # ensure all lights are active on foreground and background + has_light = False has_mesh = False for ob in scene.objects: - if ob.type == 'LAMP': + if ob.type == 'LIGHT': ob.layers = all_layers - has_lamp = True + has_light = True elif ob.type == 'MESH' and "is_ground" not in ob: has_mesh = True - # create sample lamp if there's no lamps in the scene - if not has_lamp: - lamp = self._createLamp(scene) - lamp.layers = all_layers + # create sample light if there's no lights in the scene + if not has_light: + light = self._createLight(scene) + light.layers = all_layers # create sample object if there's no meshes in the scene if not has_mesh: @@ -987,7 +987,7 @@ class CLIP_OT_setup_tracking_scene(Operator): self._setupWorld(context) self._setupCamera(context) self._setupViewport(context) - self._setupRenderLayers(context) + self._setupViewLayers(context) self._setupNodes(context) self._setupObjects(context) diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py index 2d32f84805e..b62b9310224 100644 --- a/release/scripts/startup/bl_operators/console.py +++ b/release/scripts/startup/bl_operators/console.py @@ -37,7 +37,7 @@ class ConsoleExec(Operator): bl_idname = "console.execute" bl_label = "Console Execute" - interactive = BoolProperty( + interactive: BoolProperty( options={'SKIP_SAVE'}, ) @@ -137,7 +137,7 @@ class ConsoleLanguage(Operator): bl_idname = "console.language" bl_label = "Console Language" - language = StringProperty( + language: StringProperty( name="Language", maxlen=32, ) diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py index 5bb97ff298a..44948879fe6 100644 --- a/release/scripts/startup/bl_operators/file.py +++ b/release/scripts/startup/bl_operators/file.py @@ -37,56 +37,56 @@ class WM_OT_previews_batch_generate(Operator): # ----------- # File props. - files = CollectionProperty( + files: CollectionProperty( type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}, ) - directory = StringProperty( + directory: StringProperty( maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'}, ) # Show only images/videos, and directories! - filter_blender = BoolProperty( + filter_blender: BoolProperty( default=True, options={'HIDDEN', 'SKIP_SAVE'}, ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( default=True, options={'HIDDEN', 'SKIP_SAVE'}, ) # ----------- # Own props. - use_scenes = BoolProperty( + use_scenes: BoolProperty( default=True, name="Scenes", description="Generate scenes' previews", ) - use_groups = BoolProperty( + use_collections: BoolProperty( default=True, - name="Groups", - description="Generate groups' previews", + name="Collections", + description="Generate collections' previews", ) - use_objects = BoolProperty( + use_objects: BoolProperty( default=True, name="Objects", description="Generate objects' previews", ) - use_intern_data = BoolProperty( + use_intern_data: BoolProperty( default=True, name="Mat/Tex/...", description="Generate 'internal' previews (materials, textures, images, etc.)", ) - use_trusted = BoolProperty( + use_trusted: BoolProperty( default=False, name="Trusted Blend Files", description="Enable python evaluation for selected files", ) - use_backups = BoolProperty( + use_backups: BoolProperty( default=True, name="Save Backups", description="Keep a backup (.blend1) version of the files when saving with generated previews", @@ -121,8 +121,8 @@ class WM_OT_previews_batch_generate(Operator): ]) if not self.use_scenes: cmd.append('--no_scenes') - if not self.use_groups: - cmd.append('--no_groups') + if not self.use_collections: + cmd.append('--no_collections') if not self.use_objects: cmd.append('--no_objects') if not self.use_intern_data: @@ -147,55 +147,56 @@ class WM_OT_previews_batch_clear(Operator): # ----------- # File props. - files = CollectionProperty( + files: CollectionProperty( type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}, ) - directory = StringProperty( + directory: StringProperty( maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'}, ) # Show only images/videos, and directories! - filter_blender = BoolProperty( + filter_blender: BoolProperty( default=True, options={'HIDDEN', 'SKIP_SAVE'}, ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( default=True, options={'HIDDEN', 'SKIP_SAVE'}, ) # ----------- # Own props. - use_scenes = BoolProperty( + use_scenes: BoolProperty( default=True, name="Scenes", description="Clear scenes' previews", ) - use_groups = BoolProperty(default=True, - name="Groups", - description="Clear groups' previews", - ) - use_objects = BoolProperty( + use_collections: BoolProperty( + default=True, + name="Collections", + description="Clear collections' previews", + ) + use_objects: BoolProperty( default=True, name="Objects", description="Clear objects' previews", ) - use_intern_data = BoolProperty( + use_intern_data: BoolProperty( default=True, name="Mat/Tex/...", description="Clear 'internal' previews (materials, textures, images, etc.)", ) - use_trusted = BoolProperty( + use_trusted: BoolProperty( default=False, name="Trusted Blend Files", description="Enable python evaluation for selected files", ) - use_backups = BoolProperty( + use_backups: BoolProperty( default=True, name="Save Backups", description="Keep a backup (.blend1) version of the files when saving with cleared previews", @@ -231,8 +232,8 @@ class WM_OT_previews_batch_clear(Operator): ]) if not self.use_scenes: cmd.append('--no_scenes') - if not self.use_groups: - cmd.append('--no_groups') + if not self.use_collections: + cmd.append('--no_collections') if not self.use_objects: cmd.append('--no_objects') if not self.use_intern_data: diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py index 6ee840ffc75..894808de3ed 100644 --- a/release/scripts/startup/bl_operators/freestyle.py +++ b/release/scripts/startup/bl_operators/freestyle.py @@ -34,28 +34,28 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator): bl_label = "Fill Range by Selection" bl_options = {'INTERNAL'} - type = EnumProperty( + type: EnumProperty( name="Type", description="Type of the modifier to work on", items=(("COLOR", "Color", "Color modifier type"), ("ALPHA", "Alpha", "Alpha modifier type"), ("THICKNESS", "Thickness", "Thickness modifier type")), ) - name = StringProperty( + name: StringProperty( name="Name", description="Name of the modifier to work on", ) @classmethod def poll(cls, context): - rl = context.scene.render.layers.active - return rl and rl.freestyle_settings.linesets.active + view_layer = context.view_layer + return view_layer and view_layer.freestyle_settings.linesets.active def execute(self, context): import sys scene = context.scene - rl = scene.render.layers.active - lineset = rl.freestyle_settings.linesets.active + view_layer = context.view_layer + lineset = view_layer.freestyle_settings.linesets.active linestyle = lineset.linestyle # Find the modifier to work on if self.type == 'COLOR': @@ -104,7 +104,7 @@ class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator): m.range_max = max_dist return {'FINISHED'} # Find selected mesh objects - selection = [ob for ob in scene.objects if ob.select and ob.type == 'MESH' and ob.name != ref.name] + selection = [ob for ob in scene.objects if ob.select_get() and ob.type == 'MESH' and ob.name != source.name] if selection: # Compute the min/max distance from the reference to mesh vertices min_dist = sys.float_info.max @@ -198,17 +198,17 @@ class SCENE_OT_freestyle_module_open(bpy.types.Operator): bl_label = "Open Style Module File" bl_options = {'INTERNAL'} - filepath = StringProperty(subtype='FILE_PATH') + filepath: StringProperty(subtype='FILE_PATH') - make_internal = BoolProperty( + make_internal: BoolProperty( name="Make internal", description="Make module file internal after loading", default=True) @classmethod def poll(cls, context): - rl = context.scene.render.layers.active - return rl and rl.freestyle_settings.mode == 'SCRIPT' + view_layer = context.view_layer + return view_layer and view_layer.freestyle_settings.mode == 'SCRIPT' def invoke(self, context, event): self.freestyle_module = context.freestyle_module diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index 5c5ca329cda..28e5e59d780 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -29,7 +29,7 @@ class EditExternally(Operator): bl_label = "Image Edit Externally" bl_options = {'REGISTER'} - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', ) diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index 7fb1877d191..1149d7a0dfb 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -33,7 +33,7 @@ class MeshMirrorUV(Operator): bl_label = "Copy Mirrored UV coords" bl_options = {'REGISTER', 'UNDO'} - direction = EnumProperty( + direction: EnumProperty( name="Axis Direction", items=( ('POSITIVE', "Positive", ""), @@ -41,7 +41,7 @@ class MeshMirrorUV(Operator): ), ) - precision = IntProperty( + precision: IntProperty( name="Precision", description=("Tolerance for finding vertex duplicates"), min=1, max=16, @@ -52,7 +52,7 @@ class MeshMirrorUV(Operator): @classmethod def poll(cls, context): obj = context.active_object - return (obj and obj.type == 'MESH' and obj.data.uv_textures.active) + return (obj and obj.type == 'MESH' and obj.data.uv_layers.active) def execute(self, context): DIR = (self.direction == 'NEGATIVE') @@ -205,57 +205,7 @@ class MeshSelectPrev(Operator): return {'FINISHED'} -# XXX This is hackish (going forth and back from Object mode...), to be redone once we have proper support of -# custom normals in BMesh/edit mode. -class MehsSetNormalsFromFaces(Operator): - """Set the custom vertex normals from the selected faces ones""" - bl_idname = "mesh.set_normals_from_faces" - bl_label = "Set Normals From Faces" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - return (context.mode == 'EDIT_MESH' and context.edit_object.data.polygons) - - def execute(self, context): - import mathutils - - bpy.ops.object.mode_set(mode='OBJECT') - obj = context.active_object - me = obj.data - - v2nors = {} - for p in me.polygons: - if not p.select: - continue - for lidx, vidx in zip(p.loop_indices, p.vertices): - assert(me.loops[lidx].vertex_index == vidx) - v2nors.setdefault(vidx, []).append(p.normal) - - for nors in v2nors.values(): - nors[:] = [sum(nors, mathutils.Vector((0, 0, 0))).normalized()] - - if not me.has_custom_normals: - me.create_normals_split() - me.calc_normals_split() - - normals = [] - for l in me.loops: - nor = v2nors.get(l.vertex_index, [None])[0] - if nor is None: - nor = l.normal - normals.append(nor.to_tuple()) - - me.normals_split_custom_set(normals) - - me.free_normals_split() - bpy.ops.object.mode_set(mode='EDIT') - - return {'FINISHED'} - - classes = ( - MehsSetNormalsFromFaces, MeshMirrorUV, MeshSelectNext, MeshSelectPrev, diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py index bb8f991e526..fbebee2d8a1 100644 --- a/release/scripts/startup/bl_operators/node.py +++ b/release/scripts/startup/bl_operators/node.py @@ -34,7 +34,7 @@ from bpy.props import ( class NodeSetting(PropertyGroup): - value = StringProperty( + value: StringProperty( name="Value", description="Python expression to be evaluated " "as the initial node setting", @@ -45,16 +45,16 @@ class NodeSetting(PropertyGroup): # Base class for node 'Add' operators class NodeAddOperator: - type = StringProperty( + type: StringProperty( name="Node Type", description="Node type", ) - use_transform = BoolProperty( + use_transform: BoolProperty( name="Use Transform", description="Start transform operator after inserting the node", default=False, ) - settings = CollectionProperty( + settings: CollectionProperty( name="Settings", description="Settings to be applied on the newly created node", type=NodeSetting, @@ -152,7 +152,7 @@ class NODE_OT_add_and_link_node(NodeAddOperator, Operator): bl_label = "Add and Link Node" bl_options = {'REGISTER', 'UNDO'} - link_socket_index = IntProperty( + link_socket_index: IntProperty( name="Link Socket Index", description="Index of the socket to link", ) @@ -210,7 +210,7 @@ class NODE_OT_add_search(NodeAddOperator, Operator): return item return None - node_item = EnumProperty( + node_item: EnumProperty( name="Node Type", description="Node type", items=node_enum_items, diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 91e5859d2c0..be379ec6089 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -35,19 +35,19 @@ class SelectPattern(Operator): bl_label = "Select Pattern" bl_options = {'REGISTER', 'UNDO'} - pattern = StringProperty( + pattern: StringProperty( name="Pattern", description="Name filter using '*', '?' and " "'[abc]' unix style wildcards", maxlen=64, default="*", ) - case_sensitive = BoolProperty( + case_sensitive: BoolProperty( name="Case Sensitive", description="Do a case sensitive compare", default=False, ) - extend = BoolProperty( + extend: BoolProperty( name="Extend", description="Extend the existing selection", default=True, @@ -81,16 +81,18 @@ class SelectPattern(Operator): # Can be pose bones or objects for item in items: if pattern_match(item.name, self.pattern): - item.select = True # hrmf, perhaps there should be a utility function for this. if is_ebone: + item.select = True item.select_head = True item.select_tail = True if item.use_connect: item_parent = item.parent if item_parent is not None: item_parent.select_tail = True + else: + item.select_set(action='SELECT') return {'FINISHED'} @@ -113,7 +115,7 @@ class SelectCamera(Operator): bl_label = "Select Camera" bl_options = {'REGISTER', 'UNDO'} - extend = BoolProperty( + extend: BoolProperty( name="Extend", description="Extend the selection", default=False @@ -121,6 +123,7 @@ class SelectCamera(Operator): def execute(self, context): scene = context.scene + view_layer = context.view_layer view = context.space_data if view.type == 'VIEW_3D' and not view.lock_camera_and_layers: camera = view.camera @@ -134,9 +137,9 @@ class SelectCamera(Operator): else: if not self.extend: bpy.ops.object.select_all(action='DESELECT') - scene.objects.active = camera - camera.hide = False - camera.select = True + view_layer.objects.active = camera + # camera.hide = False # XXX TODO where is this now? + camera.select_set(action='SELECT') return {'FINISHED'} return {'CANCELLED'} @@ -149,15 +152,15 @@ class SelectHierarchy(Operator): bl_label = "Select Hierarchy" bl_options = {'REGISTER', 'UNDO'} - direction = EnumProperty( + direction: EnumProperty( items=(('PARENT', "Parent", ""), ('CHILD', "Child", ""), ), name="Direction", description="Direction to select in the hierarchy", - default='PARENT') - - extend = BoolProperty( + default='PARENT', + ) + extend: BoolProperty( name="Extend", description="Extend the existing selection", default=False, @@ -169,6 +172,7 @@ class SelectHierarchy(Operator): def execute(self, context): scene = context.scene + view_layer = context.view_layer select_new = [] act_new = None @@ -202,9 +206,9 @@ class SelectHierarchy(Operator): bpy.ops.object.select_all(action='DESELECT') for obj in select_new: - obj.select = True + obj.select_set(action='SELECT') - scene.objects.active = act_new + view_layer.objects.active = act_new return {'FINISHED'} return {'CANCELLED'} @@ -217,14 +221,13 @@ class SubdivisionSet(Operator): bl_label = "Subdivision Set" bl_options = {'REGISTER', 'UNDO'} - level = IntProperty( + level: IntProperty( name="Level", min=-100, max=100, soft_min=-6, soft_max=6, default=1, ) - - relative = BoolProperty( + relative: BoolProperty( name="Relative", description=("Apply the subsurf level as an offset " "relative to the current level"), @@ -308,7 +311,7 @@ class ShapeTransfer(Operator): bl_label = "Transfer Shape Key" bl_options = {'REGISTER', 'UNDO'} - mode = EnumProperty( + mode: EnumProperty( items=(('OFFSET', "Offset", "Apply the relative positional offset", @@ -326,7 +329,7 @@ class ShapeTransfer(Operator): description="Relative shape positions to the new shape method", default='OFFSET', ) - use_clamp = BoolProperty( + use_clamp: BoolProperty( name="Clamp Offset", description=("Clamp the transformation to the distance each " "vertex moves in the original shape"), @@ -513,7 +516,7 @@ class JoinUVs(Operator): if is_editmode: bpy.ops.object.mode_set(mode='OBJECT', toggle=False) - if not mesh.uv_textures: + if not mesh.uv_layers: self.report({'WARNING'}, "Object: %s, Mesh: '%s' has no UVs" % (obj.name, mesh.name)) @@ -551,7 +554,7 @@ class JoinUVs(Operator): else: uv_other = mesh_other.uv_layers.active if not uv_other: - mesh_other.uv_textures.new() + mesh_other.uv_layers.new() uv_other = mesh_other.uv_layers.active if not uv_other: self.report({'ERROR'}, "Could not add " @@ -644,8 +647,8 @@ class MakeDupliFace(Operator): ob_new.use_dupli_faces_scale = True ob_new.dupli_faces_scale = 1.0 / SCALE_FAC - ob_inst.select = True - ob_new.select = True + ob_inst.select_set(action='SELECT') + ob_new.select_set(action='SELECT') def execute(self, context): self._main(context) @@ -664,7 +667,7 @@ class IsolateTypeRender(Operator): for obj in context.visible_objects: - if obj.select: + if obj.select_get(): obj.hide_render = False else: if obj.type == act_type: @@ -692,7 +695,7 @@ class TransformsToDeltas(Operator): bl_label = "Transforms to Deltas" bl_options = {'REGISTER', 'UNDO'} - mode = EnumProperty( + mode: EnumProperty( items=( ('ALL', "All Transforms", "Transfer location, rotation, and scale transforms"), ('LOC', "Location", "Transfer location transforms only"), @@ -703,7 +706,7 @@ class TransformsToDeltas(Operator): description="Which transforms to transfer", default='ALL', ) - reset_values = BoolProperty( + reset_values: BoolProperty( name="Reset Values", description=("Clear transform values after transferring to deltas"), default=True, @@ -850,7 +853,7 @@ class TransformsToDeltasAnim(Operator): class DupliOffsetFromCursor(Operator): - """Set offset used for DupliGroup based on cursor position""" + """Set offset used for collection instances based on cursor position""" bl_idname = "object.dupli_offset_from_cursor" bl_label = "Set Offset From Cursor" bl_options = {'INTERNAL', 'UNDO'} @@ -861,166 +864,9 @@ class DupliOffsetFromCursor(Operator): def execute(self, context): scene = context.scene - group = context.group - - group.dupli_offset = scene.cursor_location - - return {'FINISHED'} - - -class LodByName(Operator): - """Add levels of detail to this object based on object names""" - bl_idname = "object.lod_by_name" - bl_label = "Setup Levels of Detail By Name" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - return (context.active_object is not None) - - def execute(self, context): - ob = context.active_object - - prefix = "" - suffix = "" - name = "" - if ob.name.lower().startswith("lod0"): - prefix = ob.name[:4] - name = ob.name[4:] - elif ob.name.lower().endswith("lod0"): - name = ob.name[:-4] - suffix = ob.name[-4:] - else: - return {'CANCELLED'} - - level = 0 - while True: - level += 1 - - if prefix: - prefix = prefix[:3] + str(level) - if suffix: - suffix = suffix[:3] + str(level) - - lod = None - try: - lod = bpy.data.objects[prefix + name + suffix] - except KeyError: - break - - try: - ob.lod_levels[level] - except IndexError: - bpy.ops.object.lod_add() - - ob.lod_levels[level].object = lod - - return {'FINISHED'} - - -class LodClearAll(Operator): - """Remove all levels of detail from this object""" - bl_idname = "object.lod_clear_all" - bl_label = "Clear All Levels of Detail" - bl_options = {'REGISTER', 'UNDO'} - - @classmethod - def poll(cls, context): - return (context.active_object is not None) - - def execute(self, context): - ob = context.active_object - - if ob.lod_levels: - while 'CANCELLED' not in bpy.ops.object.lod_remove(): - pass - - return {'FINISHED'} - - -class LodGenerate(Operator): - """Generate levels of detail using the decimate modifier""" - bl_idname = "object.lod_generate" - bl_label = "Generate Levels of Detail" - bl_options = {'REGISTER', 'UNDO'} - - count = IntProperty( - name="Count", - default=3, - ) - target = FloatProperty( - name="Target Size", - min=0.0, max=1.0, - default=0.1, - ) - package = BoolProperty( - name="Package into Group", - default=False, - ) - - @classmethod - def poll(cls, context): - return (context.active_object is not None) - - def execute(self, context): - scene = context.scene - ob = scene.objects.active - - lod_name = ob.name - lod_suffix = "lod" - lod_prefix = "" - if lod_name.lower().endswith("lod0"): - lod_suffix = lod_name[-3:-1] - lod_name = lod_name[:-3] - elif lod_name.lower().startswith("lod0"): - lod_suffix = "" - lod_prefix = lod_name[:3] - lod_name = lod_name[4:] - - group_name = lod_name.strip(' ._') - if self.package: - try: - bpy.ops.object.group_link(group=group_name) - except TypeError: - bpy.ops.group.create(name=group_name) - - step = (1.0 - self.target) / (self.count - 1) - for i in range(1, self.count): - scene.objects.active = ob - bpy.ops.object.duplicate() - lod = context.selected_objects[0] - - scene.objects.active = ob - bpy.ops.object.lod_add() - scene.objects.active = lod - - if lod_prefix: - lod.name = lod_prefix + str(i) + lod_name - else: - lod.name = lod_name + lod_suffix + str(i) - - lod.location.y = ob.location.y + 3.0 * i - - if i == 1: - modifier = lod.modifiers.new("lod_decimate", 'DECIMATE') - else: - modifier = lod.modifiers[-1] - - modifier.ratio = 1.0 - step * i - - ob.lod_levels[i].object = lod - - if self.package: - bpy.ops.object.group_link(group=group_name) - lod.parent = ob - - if self.package: - for level in ob.lod_levels[1:]: - level.object.hide = level.object.hide_render = True + collection = context.collection - lod.select = False - ob.select = True - scene.objects.active = ob + collection.dupli_offset = scene.cursor_location return {'FINISHED'} @@ -1030,9 +876,6 @@ classes = ( DupliOffsetFromCursor, IsolateTypeRender, JoinUVs, - LodByName, - LodClearAll, - LodGenerate, MakeDupliFace, SelectCamera, SelectHierarchy, diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 11c1514e4bf..f627fd30162 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -363,7 +363,7 @@ class AlignObjects(Operator): bl_label = "Align Objects" bl_options = {'REGISTER', 'UNDO'} - bb_quality = BoolProperty( + bb_quality: BoolProperty( name="High Quality", description=( "Enables high quality calculation of the " @@ -372,7 +372,7 @@ class AlignObjects(Operator): ), default=True, ) - align_mode = EnumProperty( + align_mode: EnumProperty( name="Align Mode:", description="Side of object to use for alignment", items=( @@ -382,7 +382,7 @@ class AlignObjects(Operator): ), default='OPT_2', ) - relative_to = EnumProperty( + relative_to: EnumProperty( name="Relative To:", description="Reference location to align to", items=( @@ -393,7 +393,7 @@ class AlignObjects(Operator): ), default='OPT_4', ) - align_axis = EnumProperty( + align_axis: EnumProperty( name="Align", description="Align to axis", items=( diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index c2592f13d66..36dc1b46590 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -52,7 +52,7 @@ class QuickFur(Operator): bl_label = "Quick Fur" bl_options = {'REGISTER', 'UNDO'} - density = EnumProperty( + density: EnumProperty( name="Fur Density", items=( ('LIGHT', "Light", ""), @@ -61,13 +61,13 @@ class QuickFur(Operator): ), default='MEDIUM', ) - view_percentage = IntProperty( + view_percentage: IntProperty( name="View %", min=1, max=100, soft_min=1, soft_max=100, default=10, ) - length = FloatProperty( + length: FloatProperty( name="Length", min=0.001, max=100, soft_min=0.01, soft_max=10, @@ -118,7 +118,7 @@ class QuickExplode(Operator): bl_label = "Quick Explode" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty( + style: EnumProperty( name="Explode Style", items=( ('EXPLODE', "Explode", ""), @@ -126,40 +126,40 @@ class QuickExplode(Operator): ), default='EXPLODE', ) - amount = IntProperty( + amount: IntProperty( name="Amount of pieces", min=2, max=10000, soft_min=2, soft_max=10000, default=100, ) - frame_duration = IntProperty( + frame_duration: IntProperty( name="Duration", min=1, max=300000, soft_min=1, soft_max=10000, default=50, ) - frame_start = IntProperty( + frame_start: IntProperty( name="Start Frame", min=1, max=300000, soft_min=1, soft_max=10000, default=1, ) - frame_end = IntProperty( + frame_end: IntProperty( name="End Frame", min=1, max=300000, soft_min=1, soft_max=10000, default=10, ) - velocity = FloatProperty( + velocity: FloatProperty( name="Outwards Velocity", min=0, max=300000, soft_min=0, soft_max=10, default=1, ) - fade = BoolProperty( + fade: BoolProperty( name="Fade", description="Fade the pieces over time", default=True, @@ -226,7 +226,7 @@ class QuickExplode(Operator): if self.fade: explode.show_dead = False - uv = obj.data.uv_textures.new("Explode fade") + uv = obj.data.uv_layers.new("Explode fade") explode.particle_uv = uv.name mat = object_ensure_material(obj, "Explode Fade") @@ -306,7 +306,7 @@ class QuickSmoke(Operator): bl_label = "Quick Smoke" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty( + style: EnumProperty( name="Smoke Style", items=( ('SMOKE', "Smoke", ""), @@ -316,7 +316,7 @@ class QuickSmoke(Operator): default='SMOKE', ) - show_flows = BoolProperty( + show_flows: BoolProperty( name="Render Smoke Objects", description="Keep the smoke objects visible during rendering", default=False, @@ -369,88 +369,38 @@ class QuickSmoke(Operator): # Setup material - # Cycles - if context.scene.render.use_shading_nodes: - bpy.ops.object.material_slot_add() - - mat = bpy.data.materials.new("Smoke Domain Material") - obj.material_slots[0].material = mat - - # Make sure we use nodes - mat.use_nodes = True - - # Set node variables and clear the default nodes - tree = mat.node_tree - nodes = tree.nodes - links = tree.links - - nodes.clear() + # Cycles and Eevee + bpy.ops.object.material_slot_add() - # Create shader nodes + mat = bpy.data.materials.new("Smoke Domain Material") + obj.material_slots[0].material = mat - # Material output - node_out = nodes.new(type='ShaderNodeOutputMaterial') - node_out.location = grid_location(6, 1) + # Make sure we use nodes + mat.use_nodes = True - # Add Principled Volume - node_principled = nodes.new(type='ShaderNodeVolumePrincipled') - node_principled.location = grid_location(4, 1) - links.new(node_principled.outputs["Volume"], - node_out.inputs["Volume"]) + # Set node variables and clear the default nodes + tree = mat.node_tree + nodes = tree.nodes + links = tree.links - node_principled.inputs["Density"].default_value = 5.0 + nodes.clear() - if self.style in {'FIRE', 'BOTH'}: - node_principled.inputs["Blackbody Intensity"].default_value = 1.0 + # Create shader nodes - # Blender Internal - else: - # create a volume material with a voxel data texture for the domain - bpy.ops.object.material_slot_add() - - mat = bpy.data.materials.new("Smoke Domain Material") - obj.material_slots[0].material = mat - mat.type = 'VOLUME' - mat.volume.density = 0 - mat.volume.density_scale = 5 - mat.volume.step_size = 0.1 - - tex = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA') - tex.voxel_data.domain_object = obj - tex.voxel_data.interpolation = 'TRICUBIC_BSPLINE' - - tex_slot = mat.texture_slots.add() - tex_slot.texture = tex - tex_slot.texture_coords = 'ORCO' - tex_slot.use_map_color_emission = False - tex_slot.use_map_density = True - tex_slot.use_map_color_reflection = True - - # for fire add a second texture for flame emission - mat.volume.emission_color = Vector((0.0, 0.0, 0.0)) - tex = bpy.data.textures.new("Flame", 'VOXEL_DATA') - tex.voxel_data.domain_object = obj - tex.voxel_data.smoke_data_type = 'SMOKEFLAME' - tex.voxel_data.interpolation = 'TRICUBIC_BSPLINE' - tex.use_color_ramp = True + # Material output + node_out = nodes.new(type='ShaderNodeOutputMaterial') + node_out.location = grid_location(6, 1) - tex_slot = mat.texture_slots.add() - tex_slot.texture = tex - tex_slot.texture_coords = 'ORCO' + # Add Principled Volume + node_principled = nodes.new(type='ShaderNodeVolumePrincipled') + node_principled.location = grid_location(4, 1) + links.new(node_principled.outputs["Volume"], + node_out.inputs["Volume"]) - # add color ramp for flame color - ramp = tex.color_ramp - # dark orange - elem = ramp.elements.new(0.333) - elem.color = (0.2, 0.03, 0.0, 1.0) + node_principled.inputs["Density"].default_value = 5.0 - # yellow glow - elem = ramp.elements.new(0.666) - elem.color = (1, 0.65, 0.25, 1.0) - - mat.texture_slots[1].use_map_density = True - mat.texture_slots[1].use_map_emission = True - mat.texture_slots[1].emission_factor = 5 + if self.style in {'FIRE', 'BOTH'}: + node_principled.inputs["Blackbody Intensity"].default_value = 1.0 return {'FINISHED'} @@ -460,7 +410,7 @@ class QuickFluid(Operator): bl_label = "Quick Fluid" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty( + style: EnumProperty( name="Fluid Style", items=( ('INFLOW', "Inflow", ""), @@ -468,19 +418,19 @@ class QuickFluid(Operator): ), default='BASIC', ) - initial_velocity = FloatVectorProperty( + initial_velocity: FloatVectorProperty( name="Initial Velocity", description="Initial velocity of the fluid", min=-100.0, max=100.0, default=(0.0, 0.0, 0.0), subtype='VELOCITY', ) - show_flows = BoolProperty( + show_flows: BoolProperty( name="Render Fluid Objects", description="Keep the fluid objects visible during rendering", default=False, ) - start_baking = BoolProperty( + start_baking: BoolProperty( name="Start Fluid Bake", description=("Start baking the fluid immediately " "after creating the domain object"), @@ -554,13 +504,33 @@ class QuickFluid(Operator): mat = bpy.data.materials.new("Fluid Domain Material") obj.material_slots[0].material = mat - mat.specular_intensity = 1 - mat.specular_hardness = 100 - mat.use_transparency = True - mat.alpha = 0.0 - mat.transparency_method = 'RAYTRACE' - mat.raytrace_transparency.ior = 1.33 - mat.raytrace_transparency.depth = 4 + # Make sure we use nodes + mat.use_nodes = True + + # Set node variables and clear the default nodes + tree = mat.node_tree + nodes = tree.nodes + links = tree.links + + nodes.clear() + + # Create shader nodes + + # Material output + node_out = nodes.new(type='ShaderNodeOutputMaterial') + node_out.location = grid_location(6, 1) + + # Add Glass + node_glass = nodes.new(type='ShaderNodeBsdfGlass') + node_glass.location = grid_location(4, 1) + links.new(node_glass.outputs["BSDF"], node_out.inputs["Surface"]) + node_glass.inputs["IOR"].default_value = 1.33 + + # Add Absorption + node_absorption = nodes.new(type='ShaderNodeVolumeAbsorption') + node_absorption.location = grid_location(4, 2) + links.new(node_absorption.outputs["Volume"], node_out.inputs["Volume"]) + node_absorption.inputs["Color"].default_value = (0.8, 0.9, 1.0, 1.0) if self.start_baking: bpy.ops.fluid.bake('INVOKE_DEFAULT') diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py index dbc9461ad5a..6e2dad079ee 100644 --- a/release/scripts/startup/bl_operators/object_randomize_transform.py +++ b/release/scripts/startup/bl_operators/object_randomize_transform.py @@ -103,25 +103,25 @@ class RandomizeLocRotSize(Operator): bl_label = "Randomize Transform" bl_options = {'REGISTER', 'UNDO'} - random_seed = IntProperty( + random_seed: IntProperty( name="Random Seed", description="Seed value for the random generator", min=0, max=10000, default=0, ) - use_delta = BoolProperty( + use_delta: BoolProperty( name="Transform Delta", description=("Randomize delta transform values " "instead of regular transform"), default=False, ) - use_loc = BoolProperty( + use_loc: BoolProperty( name="Randomize Location", description="Randomize the location values", default=True, ) - loc = FloatVectorProperty( + loc: FloatVectorProperty( name="Location", description=("Maximum distance the objects " "can spread over each axis"), @@ -130,12 +130,12 @@ class RandomizeLocRotSize(Operator): default=(0.0, 0.0, 0.0), subtype='TRANSLATION', ) - use_rot = BoolProperty( + use_rot: BoolProperty( name="Randomize Rotation", description="Randomize the rotation values", default=True, ) - rot = FloatVectorProperty( + rot: FloatVectorProperty( name="Rotation", description="Maximum rotation over each axis", min=-3.141592, # math.pi @@ -143,25 +143,25 @@ class RandomizeLocRotSize(Operator): default=(0.0, 0.0, 0.0), subtype='EULER', ) - use_scale = BoolProperty( + use_scale: BoolProperty( name="Randomize Scale", description="Randomize the scale values", default=True, ) - scale_even = BoolProperty( + scale_even: BoolProperty( name="Scale Even", description="Use the same scale value for all axis", default=False, ) - '''scale_min = FloatProperty( + '''scale_min: FloatProperty( name="Minimun Scale Factor", description="Lowest scale percentage possible", min=-1.0, max=1.0, precision=3, default=0.15, )''' - scale = FloatVectorProperty( + scale: FloatVectorProperty( name="Scale", description="Maximum scale randomization over each axis", min=-100.0, diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 8852bca971d..0fe45f8fee3 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -19,9 +19,16 @@ # <pep8 compliant> import bpy -from bpy.types import Menu, Operator +from bpy.types import Menu, Operator, Panel, WindowManager from bpy.props import StringProperty, BoolProperty +# For preset popover menu +WindowManager.preset_name = StringProperty( + name="Preset Name", + description="Name for new preset", + default="New Preset" +) + class AddPresetBase: """Base preset class, only for subclassing @@ -34,22 +41,20 @@ class AddPresetBase: # only because invoke_props_popup requires. Also do not add to search menu. bl_options = {'REGISTER', 'INTERNAL'} - name = StringProperty( + name: StringProperty( name="Name", description="Name of the preset, used to make the path name", maxlen=64, options={'SKIP_SAVE'}, ) - remove_active = BoolProperty( + remove_name: BoolProperty( + default=False, + options={'HIDDEN', 'SKIP_SAVE'}, + ) + remove_active: BoolProperty( default=False, options={'HIDDEN', 'SKIP_SAVE'}, ) - - # needed for mix-ins - order = [ - "name", - "remove_active", - ] @staticmethod def as_filename(name): # could reuse for other presets @@ -85,11 +90,17 @@ class AddPresetBase: else: ext = ".py" - if not self.remove_active: - name = self.name.strip() + name = self.name.strip() + if not (self.remove_name or self.remove_active): + if not name: return {'FINISHED'} + # Reset preset name + wm = bpy.data.window_managers[0] + if name == wm.preset_name: + wm.preset_name = 'New Preset' + filename = self.as_filename(name) target_path = os.path.join("presets", self.preset_subdir) @@ -155,15 +166,16 @@ class AddPresetBase: preset_menu_class.bl_label = bpy.path.display_name(filename) else: - preset_active = preset_menu_class.bl_label + if self.remove_active: + name = preset_menu_class.bl_label # fairly sloppy but convenient. - filepath = bpy.utils.preset_find(preset_active, + filepath = bpy.utils.preset_find(name, self.preset_subdir, ext=ext) if not filepath: - filepath = bpy.utils.preset_find(preset_active, + filepath = bpy.utils.preset_find(name, self.preset_subdir, display_name=True, ext=ext) @@ -194,7 +206,7 @@ class AddPresetBase: self.name = self.as_filename(self.name.strip()) def invoke(self, context, event): - if not self.remove_active: + if not (self.remove_active or self.remove_name): wm = context.window_manager return wm.invoke_props_dialog(self) else: @@ -206,11 +218,11 @@ class ExecutePreset(Operator): bl_idname = "script.execute_preset" bl_label = "Execute a Python Preset" - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', options={'SKIP_SAVE'}, ) - menu_idname = StringProperty( + menu_idname: StringProperty( name="Menu ID Name", description="ID name of the menu this was called from", options={'SKIP_SAVE'}, @@ -241,18 +253,51 @@ class ExecutePreset(Operator): return {'FINISHED'} +class PresetMenu(Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'HEADER' + bl_label = "Presets" + path_menu = Menu.path_menu + + @classmethod + def draw_panel_header(cls, layout): + layout.emboss = 'NONE' + layout.popover( + panel=cls.__name__, + icon='PRESET', + text="", + ) + + @classmethod + def draw_menu(cls, layout, text=None): + if text is None: + text = cls.bl_label + + layout.popover( + panel=cls.__name__, + icon='PRESET', + text=text, + ) + + def draw(self, context): + layout = self.layout + layout.emboss = 'PULLDOWN_MENU' + layout.operator_context = 'EXEC_DEFAULT' + + Menu.draw_preset(self, context) + + class AddPresetRender(AddPresetBase, Operator): """Add or remove a Render Preset""" bl_idname = "render.preset_add" bl_label = "Add Render Preset" - preset_menu = "RENDER_MT_presets" + preset_menu = "RENDER_PT_presets" preset_defines = [ "scene = bpy.context.scene" ] preset_values = [ - "scene.render.field_order", "scene.render.fps", "scene.render.fps_base", "scene.render.pixel_aspect_x", @@ -260,8 +305,6 @@ class AddPresetRender(AddPresetBase, Operator): "scene.render.resolution_percentage", "scene.render.resolution_x", "scene.render.resolution_y", - "scene.render.use_fields", - "scene.render.use_fields_still", ] preset_subdir = "render" @@ -271,7 +314,7 @@ class AddPresetCamera(AddPresetBase, Operator): """Add or remove a Camera Preset""" bl_idname = "camera.preset_add" bl_label = "Add Camera Preset" - preset_menu = "CAMERA_MT_presets" + preset_menu = "CAMERA_PT_presets" preset_defines = [ "cam = bpy.context.camera" @@ -279,7 +322,7 @@ class AddPresetCamera(AddPresetBase, Operator): preset_subdir = "camera" - use_focal_length = BoolProperty( + use_focal_length: BoolProperty( name="Include Focal Length", description="Include focal length into the preset", options={'SKIP_SAVE'}, @@ -302,7 +345,7 @@ class AddPresetSafeAreas(AddPresetBase, Operator): """Add or remove a Safe Areas Preset""" bl_idname = "safe_areas.preset_add" bl_label = "Add Safe Area Preset" - preset_menu = "SAFE_AREAS_MT_presets" + preset_menu = "SAFE_AREAS_PT_presets" preset_defines = [ "safe_areas = bpy.context.scene.safe_areas" @@ -318,39 +361,11 @@ class AddPresetSafeAreas(AddPresetBase, Operator): preset_subdir = "safe_areas" -class AddPresetSSS(AddPresetBase, Operator): - """Add or remove a Subsurface Scattering Preset""" - bl_idname = "material.sss_preset_add" - bl_label = "Add SSS Preset" - preset_menu = "MATERIAL_MT_sss_presets" - - preset_defines = [ - ("material = " - "bpy.context.material.active_node_material " - "if bpy.context.material.active_node_material " - "else bpy.context.material") - ] - - preset_values = [ - "material.subsurface_scattering.back", - "material.subsurface_scattering.color", - "material.subsurface_scattering.color_factor", - "material.subsurface_scattering.error_threshold", - "material.subsurface_scattering.front", - "material.subsurface_scattering.ior", - "material.subsurface_scattering.radius", - "material.subsurface_scattering.scale", - "material.subsurface_scattering.texture_factor", - ] - - preset_subdir = "sss" - - class AddPresetCloth(AddPresetBase, Operator): """Add or remove a Cloth Preset""" bl_idname = "cloth.preset_add" bl_label = "Add Cloth Preset" - preset_menu = "CLOTH_MT_presets" + preset_menu = "CLOTH_PT_presets" preset_defines = [ "cloth = bpy.context.cloth" @@ -372,7 +387,7 @@ class AddPresetFluid(AddPresetBase, Operator): """Add or remove a Fluid Preset""" bl_idname = "fluid.preset_add" bl_label = "Add Fluid Preset" - preset_menu = "FLUID_MT_presets" + preset_menu = "FLUID_PT_presets" preset_defines = [ "fluid = bpy.context.fluid" @@ -390,7 +405,7 @@ class AddPresetHairDynamics(AddPresetBase, Operator): """Add or remove a Hair Dynamics Preset""" bl_idname = "particle.hair_dynamics_preset_add" bl_label = "Add Hair Dynamics Preset" - preset_menu = "PARTICLE_MT_hair_dynamics_presets" + preset_menu = "PARTICLE_PT_hair_dynamics_presets" preset_defines = [ "psys = bpy.context.particle_system", @@ -416,35 +431,6 @@ class AddPresetHairDynamics(AddPresetBase, Operator): ] -class AddPresetSunSky(AddPresetBase, Operator): - """Add or remove a Sky & Atmosphere Preset""" - bl_idname = "lamp.sunsky_preset_add" - bl_label = "Add Sunsky Preset" - preset_menu = "LAMP_MT_sunsky_presets" - - preset_defines = [ - "sky = bpy.context.lamp.sky" - ] - - preset_values = [ - "sky.atmosphere_extinction", - "sky.atmosphere_inscattering", - "sky.atmosphere_turbidity", - "sky.backscattered_light", - "sky.horizon_brightness", - "sky.spread", - "sky.sun_brightness", - "sky.sun_intensity", - "sky.sun_size", - "sky.sky_blend", - "sky.sky_blend_type", - "sky.sky_color_space", - "sky.sky_exposure", - ] - - preset_subdir = "sunsky" - - class AddPresetInteraction(AddPresetBase, Operator): """Add or remove an Application Interaction Preset""" bl_idname = "wm.interaction_preset_add" @@ -475,7 +461,7 @@ class AddPresetTrackingCamera(AddPresetBase, Operator): """Add or remove a Tracking Camera Intrinsics Preset""" bl_idname = "clip.camera_preset_add" bl_label = "Add Camera Preset" - preset_menu = "CLIP_MT_camera_presets" + preset_menu = "CLIP_PT_camera_presets" preset_defines = [ "camera = bpy.context.edit_movieclip.tracking.camera" @@ -483,7 +469,7 @@ class AddPresetTrackingCamera(AddPresetBase, Operator): preset_subdir = "tracking_camera" - use_focal_length = BoolProperty( + use_focal_length: BoolProperty( name="Include Focal Length", description="Include focal length into the preset", options={'SKIP_SAVE'}, @@ -509,7 +495,7 @@ class AddPresetTrackingTrackColor(AddPresetBase, Operator): """Add or remove a Clip Track Color Preset""" bl_idname = "clip.track_color_preset_add" bl_label = "Add Track Color Preset" - preset_menu = "CLIP_MT_track_color_presets" + preset_menu = "CLIP_PT_track_color_presets" preset_defines = [ "track = bpy.context.edit_movieclip.tracking.tracks.active" @@ -527,7 +513,7 @@ class AddPresetTrackingSettings(AddPresetBase, Operator): """Add or remove a motion tracking settings preset""" bl_idname = "clip.tracking_settings_preset_add" bl_label = "Add Tracking Settings Preset" - preset_menu = "CLIP_MT_tracking_settings_presets" + preset_menu = "CLIP_PT_tracking_settings_presets" preset_defines = [ "settings = bpy.context.edit_movieclip.tracking.settings" @@ -557,7 +543,7 @@ class AddPresetNodeColor(AddPresetBase, Operator): """Add or remove a Node Color Preset""" bl_idname = "node.node_color_preset_add" bl_label = "Add Node Color Preset" - preset_menu = "NODE_MT_node_color_presets" + preset_menu = "NODE_PT_node_color_presets" preset_defines = [ "node = bpy.context.active_node" @@ -608,7 +594,7 @@ class AddPresetOperator(AddPresetBase, Operator): bl_label = "Operator Preset" preset_menu = "WM_MT_operator_presets" - operator = StringProperty( + operator: StringProperty( name="Operator", maxlen=64, options={'HIDDEN', 'SKIP_SAVE'}, @@ -670,7 +656,7 @@ class AddPresetUnitsLength(AddPresetBase, Operator): """Add or remove length units preset""" bl_idname = "scene.units_length_preset_add" bl_label = "Add Length Units Preset" - preset_menu = "SCENE_MT_units_length_presets" + preset_menu = "SCENE_PT_units_length_presets" preset_defines = [ "scene = bpy.context.scene" @@ -684,6 +670,42 @@ class AddPresetUnitsLength(AddPresetBase, Operator): preset_subdir = "units_length" +class AddPresetGpencilBrush(AddPresetBase, Operator): + """Add or remove grease pencil brush preset""" + bl_idname = "scene.gpencil_brush_preset_add" + bl_label = "Add Grease Pencil Brush Preset" + preset_menu = "VIEW3D_PT_gpencil_brush_presets" + + preset_defines = [ + "brush = bpy.context.active_gpencil_brush", + "settings = brush.gpencil_settings" + ] + + preset_values = [ + "settings.input_samples", + "settings.active_smooth_factor", + "settings.angle", + "settings.angle_factor", + "settings.use_stabilizer", + "brush.smooth_stroke_radius", + "brush.smooth_stroke_factor", + "settings.pen_smooth_factor", + "settings.pen_smooth_steps", + "settings.pen_thick_smooth_factor", + "settings.pen_thick_smooth_steps", + "settings.pen_subdivision_steps", + "settings.random_subdiv", + "settings.enable_random", + "settings.random_pressure", + "settings.random_strength", + "settings.uv_random", + "settings.pen_jitter", + "settings.use_jitter_pressure", + ] + + preset_subdir = "gpencil_brush" + + classes = ( AddPresetCamera, AddPresetCloth, @@ -695,13 +717,12 @@ classes = ( AddPresetNodeColor, AddPresetOperator, AddPresetRender, - AddPresetSSS, AddPresetSafeAreas, - AddPresetSunSky, AddPresetTrackingCamera, AddPresetTrackingSettings, AddPresetTrackingTrackColor, AddPresetUnitsLength, + AddPresetGpencilBrush, ExecutePreset, WM_MT_operator_presets, ) diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py index 8fbc9b29b46..6b76fb96b62 100644 --- a/release/scripts/startup/bl_operators/rigidbody.py +++ b/release/scripts/startup/bl_operators/rigidbody.py @@ -60,17 +60,17 @@ class CopyRigidbodySettings(Operator): def execute(self, context): obj_act = context.object - scene = context.scene + view_layer = context.view_layer # deselect all but mesh objects for o in context.selected_objects: if o.type != 'MESH': - o.select = False + o.select_set(action='DESELECT') elif o.rigid_body is None: # Add rigidbody to object! - scene.objects.active = o + view_layer.objects.active = o bpy.ops.rigidbody.object_add() - scene.objects.active = obj_act + view_layer.objects.active = obj_act objects = context.selected_objects if objects: @@ -92,19 +92,19 @@ class BakeToKeyframes(Operator): bl_label = "Bake To Keyframes" bl_options = {'REGISTER', 'UNDO'} - frame_start = IntProperty( + frame_start: IntProperty( name="Start Frame", description="Start frame for baking", min=0, max=300000, default=1, ) - frame_end = IntProperty( + frame_end: IntProperty( name="End Frame", description="End frame for baking", min=1, max=300000, default=250, ) - step = IntProperty( + step: IntProperty( name="Frame Step", description="Frame Step", min=1, max=120, @@ -127,7 +127,7 @@ class BakeToKeyframes(Operator): # filter objects selection for obj in context.selected_objects: if not obj.rigid_body or obj.rigid_body.type != 'ACTIVE': - obj.select = False + obj.select_set(action='DESELECT') objects = context.selected_objects @@ -216,7 +216,7 @@ class ConnectRigidBodies(Operator): bl_label = "Connect Rigid Bodies" bl_options = {'REGISTER', 'UNDO'} - con_type = EnumProperty( + con_type: EnumProperty( name="Type", description="Type of generated constraint", # XXX Would be nice to get icons too, but currently not possible ;) @@ -226,7 +226,7 @@ class ConnectRigidBodies(Operator): ), default='FIXED', ) - pivot_type = EnumProperty( + pivot_type: EnumProperty( name="Location", description="Constraint pivot location", items=( @@ -236,7 +236,7 @@ class ConnectRigidBodies(Operator): ), default='CENTER', ) - connection_pattern = EnumProperty( + connection_pattern: EnumProperty( name="Connection Pattern", description="Pattern used to connect objects", items=( @@ -265,8 +265,8 @@ class ConnectRigidBodies(Operator): ob = bpy.data.objects.new("Constraint", object_data=None) ob.location = loc context.scene.objects.link(ob) - context.scene.objects.active = ob - ob.select = True + context.view_layer.objects.active = ob + ob.select_set(action='SELECT') bpy.ops.rigidbody.constraint_add() con_obj = context.active_object @@ -278,7 +278,7 @@ class ConnectRigidBodies(Operator): con.object2 = object2 def execute(self, context): - scene = context.scene + view_layer = context.view_layer objects = context.selected_objects obj_act = context.active_object change = False @@ -311,8 +311,8 @@ class ConnectRigidBodies(Operator): # restore selection bpy.ops.object.select_all(action='DESELECT') for obj in objects: - obj.select = True - scene.objects.active = obj_act + obj.select_set(action='SELECT') + view_layer.objects.active = obj_act return {'FINISHED'} else: self.report({'WARNING'}, "No other objects selected") diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py index c9a7aa93805..b1152157cf8 100644 --- a/release/scripts/startup/bl_operators/sequencer.py +++ b/release/scripts/startup/bl_operators/sequencer.py @@ -82,7 +82,7 @@ class SequencerCutMulticam(Operator): bl_label = "Cut multicam" bl_options = {'REGISTER', 'UNDO'} - camera = IntProperty( + camera: IntProperty( name="Camera", min=1, max=32, soft_min=1, soft_max=32, diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index 72445be6950..5c870849cc5 100644 --- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py +++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py @@ -30,8 +30,8 @@ def extend(obj, operator, EXTEND_MODE): import bmesh me = obj.data # script will fail without UVs - if not me.uv_textures: - me.uv_textures.new() + if not me.uv_layers: + me.uv_layers.new() bm = bmesh.from_edit_mesh(me) @@ -226,7 +226,7 @@ class FollowActiveQuads(Operator): bl_label = "Follow Active Quads" bl_options = {'REGISTER', 'UNDO'} - mode = bpy.props.EnumProperty( + mode: bpy.props.EnumProperty( name="Edge Length Mode", description="Method to space UV edge loops", items=(('EVEN', "Even", "Space all UVs evenly"), diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 0b0dd58e80f..b866fb1ce40 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -275,12 +275,12 @@ def lightmap_uvpack(meshes, face_groups.append(faces) if PREF_NEW_UVLAYER: - me.uv_textures.new() + me.uv_layers.new() # Add face UV if it does not exist. # All new faces are selected. - if not me.uv_textures: - me.uv_textures.new() + if not me.uv_layers: + me.uv_layers.new() for face_sel in face_groups: print("\nStarting unwrap") @@ -538,6 +538,9 @@ def lightmap_uvpack(meshes, print("done") if PREF_APPLY_IMAGE: + pass + # removed with texface + ''' if not PREF_PACK_IN_ONE: image = bpy.data.images.new(name="lightmap", width=PREF_IMG_PX_SIZE, @@ -545,8 +548,8 @@ def lightmap_uvpack(meshes, ) for f in face_sel: - # f.image = image - f.id_data.uv_textures.active.data[f.index].image = image # XXX25 + f.image = image + ''' for me in meshes: me.update() @@ -576,7 +579,7 @@ def unwrap(operator, context, **kwargs): # define list of meshes meshes = [] if PREF_ACT_ONLY: - obj = context.scene.objects.active + obj = context.view_layer.objects.active if obj and obj.type == 'MESH': meshes = [obj.data] else: @@ -613,7 +616,7 @@ class LightMapPack(Operator): # This fixes infinite image creation reported there [#30968] (sergey) bl_options = {'UNDO'} - PREF_CONTEXT = bpy.props.EnumProperty( + PREF_CONTEXT: bpy.props.EnumProperty( name="Selection", items=( ('SEL_FACES', "Selected Faces", "Space all UVs evenly"), @@ -623,7 +626,7 @@ class LightMapPack(Operator): ) # Image & UVs... - PREF_PACK_IN_ONE = BoolProperty( + PREF_PACK_IN_ONE: BoolProperty( name="Share Tex Space", description=( "Objects Share texture space, map all objects " @@ -631,12 +634,12 @@ class LightMapPack(Operator): ), default=True, ) - PREF_NEW_UVLAYER = BoolProperty( + PREF_NEW_UVLAYER: BoolProperty( name="New UV Map", description="Create a new UV map for every mesh packed", default=False, ) - PREF_APPLY_IMAGE = BoolProperty( + PREF_APPLY_IMAGE: BoolProperty( name="New Image", description=( "Assign new images for every mesh (only one if " @@ -644,20 +647,20 @@ class LightMapPack(Operator): ), default=False, ) - PREF_IMG_PX_SIZE = IntProperty( + PREF_IMG_PX_SIZE: IntProperty( name="Image Size", description="Width and Height for the new image", min=64, max=5000, default=512, ) # UV Packing... - PREF_BOX_DIV = IntProperty( + PREF_BOX_DIV: IntProperty( name="Pack Quality", description="Pre Packing before the complex boxpack", min=1, max=48, default=12, ) - PREF_MARGIN_DIV = FloatProperty( + PREF_MARGIN_DIV: FloatProperty( name="Margin", description="Size of the margin as a division of the UV", min=0.001, max=1.0, diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index f0b1f934e38..fe15b9fa345 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -816,8 +816,8 @@ def main(context, # Tag as used me.tag = True - if not me.uv_textures: # Mesh has no UV Coords, don't bother. - me.uv_textures.new() + if not me.uv_layers: # Mesh has no UV Coords, don't bother. + me.uv_layers.new() uv_layer = me.uv_layers.active.data me_verts = list(me.vertices) @@ -1055,31 +1055,31 @@ class SmartProject(Operator): bl_label = "Smart UV Project" bl_options = {'REGISTER', 'UNDO'} - angle_limit = FloatProperty( + angle_limit: FloatProperty( name="Angle Limit", description="Lower for more projection groups, higher for less distortion", min=1.0, max=89.0, default=66.0, ) - island_margin = FloatProperty( + island_margin: FloatProperty( name="Island Margin", description="Margin to reduce bleed from adjacent islands", unit='LENGTH', subtype='DISTANCE', min=0.0, max=1.0, default=0.0, ) - user_area_weight = FloatProperty( + user_area_weight: FloatProperty( name="Area Weight", description="Weight projections vector by faces with larger areas", min=0.0, max=1.0, default=0.0, ) - use_aspect = BoolProperty( + use_aspect: BoolProperty( name="Correct Aspect", description="Map UVs taking image aspect ratio into account", default=True ) - stretch_to_bounds = BoolProperty( + stretch_to_bounds: BoolProperty( name="Stretch to UV Bounds", description="Stretch the final output to texture bounds", default=True, diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py index 1173e0047bb..335c3d8bbda 100644 --- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py +++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py @@ -138,33 +138,33 @@ class VertexPaintDirt(Operator): bl_label = "Dirty Vertex Colors" bl_options = {'REGISTER', 'UNDO'} - blur_strength = FloatProperty( + blur_strength: FloatProperty( name="Blur Strength", description="Blur strength per iteration", min=0.01, max=1.0, default=1.0, ) - blur_iterations = IntProperty( + blur_iterations: IntProperty( name="Blur Iterations", description="Number of times to blur the colors (higher blurs more)", min=0, max=40, default=1, ) - clean_angle = FloatProperty( + clean_angle: FloatProperty( name="Highlight Angle", description="Less than 90 limits the angle used in the tonal range", min=0.0, max=pi, default=pi, unit="ROTATION", ) - dirt_angle = FloatProperty( + dirt_angle: FloatProperty( name="Dirt Angle", description="Less than 90 limits the angle used in the tonal range", min=0.0, max=pi, default=0.0, unit="ROTATION", ) - dirt_only = BoolProperty( + dirt_only: BoolProperty( name="Dirt Only", description="Don't calculate cleans for convex areas", default=False, diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py index f56c83be7d1..b43f4446802 100644 --- a/release/scripts/startup/bl_operators/view3d.py +++ b/release/scripts/startup/bl_operators/view3d.py @@ -143,37 +143,37 @@ class VIEW3D_OT_select_or_deselect_all(Operator): bl_idname = "view3d.select_or_deselect_all" bl_options = {'UNDO'} - extend = BoolProperty( + extend: BoolProperty( name="Extend", description="Extend selection instead of deselecting everything first", default=False, ) - toggle = BoolProperty( + toggle: BoolProperty( name="Toggle", description="Toggle the selection", default=False, ) - deselect = BoolProperty( + deselect: BoolProperty( name="Deselect", description="Remove from selection", default=False, ) - center = BoolProperty( + center: BoolProperty( name="Center", description="Use the object center when selecting, in editmode used to extend object selection", default=False, ) - enumerate = BoolProperty( + enumerate: BoolProperty( name="Enumerate", description="List objects under the mouse (object mode only)", default=False, ) - object = BoolProperty( + object: BoolProperty( name="Object", description="Use object selection (editmode only)", default=False, diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index edca3a521ee..0ccdd3cf5c6 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -19,13 +19,17 @@ # <pep8 compliant> import bpy -from bpy.types import Operator +from bpy.types import ( + Operator, + OperatorFileListElement +) from bpy.props import ( BoolProperty, EnumProperty, FloatProperty, IntProperty, StringProperty, + CollectionProperty, ) from bpy.app.translations import pgettext_tip as tip_ @@ -55,6 +59,15 @@ rna_relative_prop = BoolProperty( default=False, ) +rna_space_type_prop = EnumProperty( + name="Type", + items=tuple( + (e.identifier, e.name, "", e. value) + for e in bpy.types.Space.bl_rna.properties["type"].enum_items + ), + default='EMPTY', +) + def context_path_validate(context, data_path): try: @@ -149,12 +162,12 @@ class BRUSH_OT_active_index_set(Operator): bl_idname = "brush.active_index_set" bl_label = "Set Brush Number" - mode = StringProperty( + mode: StringProperty( name="Mode", description="Paint mode to set brush for", maxlen=1024, ) - index = IntProperty( + index: IntProperty( name="Number", description="Brush number", ) @@ -186,8 +199,8 @@ class WM_OT_context_set_boolean(Operator): bl_label = "Context Set Boolean" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = BoolProperty( + data_path: rna_path_prop + value: BoolProperty( name="Value", description="Assignment value", default=True, @@ -202,13 +215,13 @@ class WM_OT_context_set_int(Operator): # same as enum bl_label = "Context Set" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = IntProperty( + data_path: rna_path_prop + value: IntProperty( name="Value", description="Assign value", default=0, ) - relative = rna_relative_prop + relative: rna_relative_prop execute = execute_context_assign @@ -219,8 +232,8 @@ class WM_OT_context_scale_float(Operator): bl_label = "Context Scale Float" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = FloatProperty( + data_path: rna_path_prop + value: FloatProperty( name="Value", description="Assign value", default=1.0, @@ -247,13 +260,13 @@ class WM_OT_context_scale_int(Operator): bl_label = "Context Scale Int" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = FloatProperty( + data_path: rna_path_prop + value: FloatProperty( name="Value", description="Assign value", default=1.0, ) - always_step = BoolProperty( + always_step: BoolProperty( name="Always Step", description="Always adjust the value by a minimum of 1 when 'value' is not 1.0", default=True, @@ -290,13 +303,13 @@ class WM_OT_context_set_float(Operator): # same as enum bl_label = "Context Set Float" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = FloatProperty( + data_path: rna_path_prop + value: FloatProperty( name="Value", description="Assignment value", default=0.0, ) - relative = rna_relative_prop + relative: rna_relative_prop execute = execute_context_assign @@ -307,8 +320,8 @@ class WM_OT_context_set_string(Operator): # same as enum bl_label = "Context Set String" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = StringProperty( + data_path: rna_path_prop + value: StringProperty( name="Value", description="Assign value", maxlen=1024, @@ -323,8 +336,8 @@ class WM_OT_context_set_enum(Operator): bl_label = "Context Set Enum" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = StringProperty( + data_path: rna_path_prop + value: StringProperty( name="Value", description="Assignment value (as a string)", maxlen=1024, @@ -339,8 +352,8 @@ class WM_OT_context_set_value(Operator): bl_label = "Context Set Value" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = StringProperty( + data_path: rna_path_prop + value: StringProperty( name="Value", description="Assignment value (as a string)", maxlen=1024, @@ -360,7 +373,7 @@ class WM_OT_context_toggle(Operator): bl_label = "Context Toggle" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop + data_path: rna_path_prop def execute(self, context): data_path = self.data_path @@ -379,13 +392,13 @@ class WM_OT_context_toggle_enum(Operator): bl_label = "Context Toggle Values" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value_1 = StringProperty( + data_path: rna_path_prop + value_1: StringProperty( name="Value", description="Toggle enum", maxlen=1024, ) - value_2 = StringProperty( + value_2: StringProperty( name="Value", description="Toggle enum", maxlen=1024, @@ -418,9 +431,9 @@ class WM_OT_context_cycle_int(Operator): bl_label = "Context Int Cycle" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - reverse = rna_reverse_prop - wrap = rna_wrap_prop + data_path: rna_path_prop + reverse: rna_reverse_prop + wrap: rna_wrap_prop def execute(self, context): data_path = self.data_path @@ -454,9 +467,9 @@ class WM_OT_context_cycle_enum(Operator): bl_label = "Context Enum Cycle" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - reverse = rna_reverse_prop - wrap = rna_wrap_prop + data_path: rna_path_prop + reverse: rna_reverse_prop + wrap: rna_wrap_prop def execute(self, context): data_path = self.data_path @@ -511,8 +524,8 @@ class WM_OT_context_cycle_array(Operator): bl_label = "Context Array Cycle" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - reverse = rna_reverse_prop + data_path: rna_path_prop + reverse: rna_reverse_prop def execute(self, context): data_path = self.data_path @@ -536,7 +549,8 @@ class WM_OT_context_menu_enum(Operator): bl_idname = "wm.context_menu_enum" bl_label = "Context Enum Menu" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop + + data_path: rna_path_prop def execute(self, context): data_path = self.data_path @@ -562,7 +576,8 @@ class WM_OT_context_pie_enum(Operator): bl_idname = "wm.context_pie_enum" bl_label = "Context Enum Pie" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop + + data_path: rna_path_prop def invoke(self, context, event): wm = context.window_manager @@ -589,12 +604,13 @@ class WM_OT_operator_pie_enum(Operator): bl_idname = "wm.operator_pie_enum" bl_label = "Operator Enum Pie" bl_options = {'UNDO', 'INTERNAL'} - data_path = StringProperty( + + data_path: StringProperty( name="Operator", description="Operator name (in python as string)", maxlen=1024, ) - prop_string = StringProperty( + prop_string: StringProperty( name="Property", description="Property name (as a string)", maxlen=1024, @@ -633,8 +649,8 @@ class WM_OT_context_set_id(Operator): bl_label = "Set Library ID" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path_prop - value = StringProperty( + data_path: rna_path_prop + value: StringProperty( name="Value", description="Assign value", maxlen=1024, @@ -684,10 +700,10 @@ class WM_OT_context_collection_boolean_set(Operator): bl_label = "Context Collection Boolean Set" bl_options = {'UNDO', 'REGISTER', 'INTERNAL'} - data_path_iter = data_path_iter - data_path_item = data_path_item + data_path_iter: data_path_iter + data_path_item: data_path_item - type = EnumProperty( + type: EnumProperty( name="Type", items=(('TOGGLE', "Toggle", ""), ('ENABLE', "Enable", ""), @@ -743,22 +759,22 @@ class WM_OT_context_modal_mouse(Operator): bl_label = "Context Modal Mouse" bl_options = {'GRAB_CURSOR', 'BLOCKING', 'UNDO', 'INTERNAL'} - data_path_iter = data_path_iter - data_path_item = data_path_item - header_text = StringProperty( + data_path_iter: data_path_iter + data_path_item: data_path_item + header_text: StringProperty( name="Header Text", description="Text to display in header during scale", ) - input_scale = FloatProperty( + input_scale: FloatProperty( description="Scale the mouse movement by this value before applying the delta", default=0.01, ) - invert = BoolProperty( + invert: BoolProperty( description="Invert the mouse input", default=False, ) - initial_x = IntProperty(options={'HIDDEN'}) + initial_x: IntProperty(options={'HIDDEN'}) def _values_store(self, context): data_path_iter = self.data_path_iter @@ -851,7 +867,7 @@ class WM_OT_url_open(Operator): bl_label = "" bl_options = {'INTERNAL'} - url = StringProperty( + url: StringProperty( name="URL", description="URL to open", ) @@ -868,7 +884,7 @@ class WM_OT_path_open(Operator): bl_label = "" bl_options = {'INTERNAL'} - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', options={'SKIP_SAVE'}, ) @@ -983,7 +999,7 @@ class WM_OT_doc_view_manual(Operator): bl_idname = "wm.doc_view_manual" bl_label = "View Manual" - doc_id = doc_id + doc_id: doc_id @staticmethod def _find_reference(rna_id, url_mapping, verbose=True): @@ -1037,7 +1053,7 @@ class WM_OT_doc_view(Operator): bl_idname = "wm.doc_view" bl_label = "View Documentation" - doc_id = doc_id + doc_id: doc_id if bpy.app.version_cycle == "release": _prefix = ("https://docs.blender.org/api/blender_python_api_current") else: @@ -1089,6 +1105,11 @@ rna_use_soft_limits = BoolProperty( name="Use Soft Limits", ) +rna_is_overridable_static = BoolProperty( + name="Is Statically Overridable", + default=False, +) + class WM_OT_properties_edit(Operator): bl_idname = "wm.properties_edit" @@ -1096,15 +1117,16 @@ class WM_OT_properties_edit(Operator): # register only because invoke_props_popup requires. bl_options = {'REGISTER', 'INTERNAL'} - data_path = rna_path - property = rna_property - value = rna_value - min = rna_min - max = rna_max - use_soft_limits = rna_use_soft_limits - soft_min = rna_min - soft_max = rna_max - description = StringProperty( + data_path: rna_path + property: rna_property + value: rna_value + min: rna_min + max: rna_max + use_soft_limits: rna_use_soft_limits + is_overridable_static: rna_is_overridable_static + soft_min: rna_min + soft_max: rna_max + description: StringProperty( name="Tooltip", ) @@ -1154,6 +1176,9 @@ class WM_OT_properties_edit(Operator): # print(exec_str) exec(exec_str) + exec_str = "item.property_overridable_static_set('[\"%s\"]', %s)" % (prop, self.is_overridable_static) + exec(exec_str) + rna_idprop_ui_prop_update(item, prop) self._last_prop[:] = [prop] @@ -1281,7 +1306,9 @@ class WM_OT_properties_edit(Operator): row.prop(self, "min") row.prop(self, "max") - layout.prop(self, "use_soft_limits") + row = layout.row() + row.prop(self, "use_soft_limits") + row.prop(self, "is_overridable_static") row = layout.row(align=True) row.enabled = self.use_soft_limits @@ -1295,7 +1322,7 @@ class WM_OT_properties_add(Operator): bl_label = "Add Property" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path + data_path: rna_path def execute(self, context): from rna_prop_ui import ( @@ -1338,7 +1365,7 @@ class WM_OT_properties_context_change(Operator): bl_label = "" bl_options = {'INTERNAL'} - context = StringProperty( + context: StringProperty( name="Context", maxlen=64, ) @@ -1354,8 +1381,8 @@ class WM_OT_properties_remove(Operator): bl_label = "Remove Property" bl_options = {'UNDO', 'INTERNAL'} - data_path = rna_path - property = rna_property + data_path: rna_path + property: rna_property def execute(self, context): from rna_prop_ui import ( @@ -1376,7 +1403,7 @@ class WM_OT_keyconfig_activate(Operator): bl_idname = "wm.keyconfig_activate" bl_label = "Activate Keyconfig" - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', ) @@ -1411,7 +1438,7 @@ class WM_OT_appconfig_activate(Operator): bl_idname = "wm.appconfig_activate" bl_label = "Activate Application Configuration" - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', ) @@ -1436,7 +1463,7 @@ class WM_OT_sysinfo(Operator): bl_idname = "wm.sysinfo" bl_label = "Save System Info" - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', options={'SKIP_SAVE'}, ) @@ -1492,54 +1519,6 @@ class WM_OT_copy_prev_settings(Operator): return {'CANCELLED'} -class WM_OT_blenderplayer_start(Operator): - """Launch the blender-player with the current blend-file""" - bl_idname = "wm.blenderplayer_start" - bl_label = "Start Game In Player" - - def execute(self, context): - import os - import sys - import subprocess - - gs = context.scene.game_settings - - # these remain the same every execution - blender_bin_path = bpy.app.binary_path - blender_bin_dir = os.path.dirname(blender_bin_path) - ext = os.path.splitext(blender_bin_path)[-1] - player_path = os.path.join(blender_bin_dir, "blenderplayer" + ext) - # done static vars - - if sys.platform == "darwin": - player_path = os.path.join(blender_bin_dir, "../../../blenderplayer.app/Contents/MacOS/blenderplayer") - - if not os.path.exists(player_path): - self.report({'ERROR'}, "Player path: %r not found" % player_path) - return {'CANCELLED'} - - filepath = bpy.data.filepath + '~' if bpy.data.is_saved else os.path.join(bpy.app.tempdir, "game.blend") - bpy.ops.wm.save_as_mainfile('EXEC_DEFAULT', filepath=filepath, copy=True) - - # start the command line call with the player path - args = [player_path] - - # handle some UI options as command line arguments - args.extend([ - "-g", "show_framerate", "=", "%d" % gs.show_framerate_profile, - "-g", "show_profile", "=", "%d" % gs.show_framerate_profile, - "-g", "show_properties", "=", "%d" % gs.show_debug_properties, - "-g", "ignore_deprecation_warnings", "=", "%d" % (not gs.use_deprecation_warnings), - ]) - - # finish the call with the path to the blend file - args.append(filepath) - - subprocess.call(args) - os.remove(filepath) - return {'FINISHED'} - - class WM_OT_keyconfig_test(Operator): """Test key-config for conflicts""" bl_idname = "wm.keyconfig_test" @@ -1562,26 +1541,26 @@ class WM_OT_keyconfig_import(Operator): bl_idname = "wm.keyconfig_import" bl_label = "Import Key Configuration..." - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', default="keymap.py", ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) - filter_text = BoolProperty( + filter_text: BoolProperty( name="Filter text", default=True, options={'HIDDEN'}, ) - filter_python = BoolProperty( + filter_python: BoolProperty( name="Filter python", default=True, options={'HIDDEN'}, ) - keep_original = BoolProperty( + keep_original: BoolProperty( name="Keep original", description="Keep original file after copying to configuration folder", default=True, @@ -1629,26 +1608,26 @@ class WM_OT_keyconfig_export(Operator): bl_idname = "wm.keyconfig_export" bl_label = "Export Key Configuration..." - all = BoolProperty( + all: BoolProperty( name="All Keymaps", default=False, description="Write all keymaps (not just user modified)", ) - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', default="keymap.py", ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) - filter_text = BoolProperty( + filter_text: BoolProperty( name="Filter text", default=True, options={'HIDDEN'}, ) - filter_python = BoolProperty( + filter_python: BoolProperty( name="Filter python", default=True, options={'HIDDEN'}, @@ -1665,7 +1644,7 @@ class WM_OT_keyconfig_export(Operator): wm = context.window_manager - keyconfig_utils.keyconfig_export( + keyconfig_utils.keyconfig_export_as_data( wm, wm.keyconfigs.active, self.filepath, @@ -1685,7 +1664,7 @@ class WM_OT_keymap_restore(Operator): bl_idname = "wm.keymap_restore" bl_label = "Restore Key Map(s)" - all = BoolProperty( + all: BoolProperty( name="All Keymaps", description="Restore all keymaps to default", ) @@ -1708,7 +1687,7 @@ class WM_OT_keyitem_restore(Operator): bl_idname = "wm.keyitem_restore" bl_label = "Restore Key Map Item" - item_id = IntProperty( + item_id: IntProperty( name="Item Identifier", description="Identifier of the item to remove", ) @@ -1755,7 +1734,7 @@ class WM_OT_keyitem_remove(Operator): bl_idname = "wm.keyitem_remove" bl_label = "Remove Key Map Item" - item_id = IntProperty( + item_id: IntProperty( name="Item Identifier", description="Identifier of the item to remove", ) @@ -1823,7 +1802,7 @@ class WM_OT_addon_enable(Operator): bl_idname = "wm.addon_enable" bl_label = "Enable Add-on" - module = StringProperty( + module: StringProperty( name="Module", description="Module name of the add-on to enable", ) @@ -1869,7 +1848,7 @@ class WM_OT_addon_disable(Operator): bl_idname = "wm.addon_disable" bl_label = "Disable Add-on" - module = StringProperty( + module: StringProperty( name="Module", description="Module name of the add-on to disable", ) @@ -1893,25 +1872,56 @@ class WM_OT_addon_disable(Operator): return {'FINISHED'} +class WM_OT_owner_enable(Operator): + """Enable workspace owner ID""" + bl_idname = "wm.owner_enable" + bl_label = "Enable Add-on" + + owner_id: StringProperty( + name="UI Tag", + ) + + def execute(self, context): + workspace = context.workspace + workspace.owner_ids.new(self.owner_id) + return {'FINISHED'} + + +class WM_OT_owner_disable(Operator): + """Enable workspace owner ID""" + bl_idname = "wm.owner_disable" + bl_label = "Disable UI Tag" + + owner_id: StringProperty( + name="UI Tag", + ) + + def execute(self, context): + workspace = context.workspace + owner_id = workspace.owner_ids[self.owner_id] + workspace.owner_ids.remove(owner_id) + return {'FINISHED'} + + class WM_OT_theme_install(Operator): """Load and apply a Blender XML theme file""" bl_idname = "wm.theme_install" bl_label = "Install Theme..." - overwrite = BoolProperty( + overwrite: BoolProperty( name="Overwrite", description="Remove existing theme file if exists", default=True, ) - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) - filter_glob = StringProperty( + filter_glob: StringProperty( default="*.xml", options={'HIDDEN'}, ) @@ -1975,31 +1985,31 @@ class WM_OT_addon_install(Operator): bl_idname = "wm.addon_install" bl_label = "Install Add-on from File..." - overwrite = BoolProperty( + overwrite: BoolProperty( name="Overwrite", description="Remove existing add-ons with the same ID", default=True, ) - target = EnumProperty( + target: EnumProperty( name="Target Path", items=(('DEFAULT', "Default", ""), ('PREFS', "User Prefs", "")), ) - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) - filter_python = BoolProperty( + filter_python: BoolProperty( name="Filter python", default=True, options={'HIDDEN'}, ) - filter_glob = StringProperty( + filter_glob: StringProperty( default="*.py;*.zip", options={'HIDDEN'}, ) @@ -2129,7 +2139,7 @@ class WM_OT_addon_remove(Operator): bl_idname = "wm.addon_remove" bl_label = "Remove Add-on" - module = StringProperty( + module: StringProperty( name="Module", description="Module name of the add-on to remove", ) @@ -2189,7 +2199,7 @@ class WM_OT_addon_expand(Operator): bl_label = "" bl_options = {'INTERNAL'} - module = StringProperty( + module: StringProperty( name="Module", description="Module name of the add-on to expand", ) @@ -2213,7 +2223,7 @@ class WM_OT_addon_userpref_show(Operator): bl_label = "" bl_options = {'INTERNAL'} - module = StringProperty( + module: StringProperty( name="Module", description="Module name of the add-on to expand", ) @@ -2244,21 +2254,21 @@ class WM_OT_app_template_install(Operator): bl_idname = "wm.app_template_install" bl_label = "Install Template from File..." - overwrite = BoolProperty( + overwrite: BoolProperty( name="Overwrite", description="Remove existing template with the same ID", default=True, ) - filepath = StringProperty( + filepath: StringProperty( subtype='FILE_PATH', ) - filter_folder = BoolProperty( + filter_folder: BoolProperty( name="Filter folders", default=True, options={'HIDDEN'}, ) - filter_glob = StringProperty( + filter_glob: StringProperty( default="*.zip", options={'HIDDEN'}, ) @@ -2338,6 +2348,180 @@ class WM_OT_app_template_install(Operator): return {'RUNNING_MODAL'} +class WM_OT_tool_set_by_name(Operator): + """Set the tool by name (for keymaps)""" + bl_idname = "wm.tool_set_by_name" + bl_label = "Set Tool By Name" + + name: StringProperty( + name="Text", + description="Display name of the tool", + ) + cycle: BoolProperty( + name="Cycle", + description="Cycle through tools in this group", + default=False, + options={'SKIP_SAVE'}, + ) + + space_type: rna_space_type_prop + + def execute(self, context): + from bl_ui.space_toolsystem_common import ( + activate_by_name, + activate_by_name_or_cycle, + ) + + if self.properties.is_property_set("space_type"): + space_type = self.space_type + else: + space_type = context.space_data.type + + fn = activate_by_name_or_cycle if self.cycle else activate_by_name + if fn(context, space_type, self.name): + return {'FINISHED'} + else: + self.report({'WARNING'}, f"Tool {self.name!r} not found.") + return {'CANCELLED'} + + +class WM_OT_toolbar(Operator): + bl_idname = "wm.toolbar" + bl_label = "Toolbar" + + def execute(self, context): + from bl_ui.space_toolsystem_common import ( + ToolSelectPanelHelper, + keymap_from_context, + ) + space_type = context.space_data.type + + cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) + if cls is None: + self.report({'WARNING'}, f"Toolbar not found for {space_type!r}") + return {'CANCELLED'} + + wm = context.window_manager + keymap = keymap_from_context(context, space_type) + + def draw_menu(popover, context): + layout = popover.layout + + layout.operator_context = 'INVOKE_DEFAULT' + layout.operator("wm.search_menu", text="Search Commands...", icon='VIEWZOOM') + + cls.draw_cls(layout, context, detect_layout=False, scale_y=1.0) + + wm.popover(draw_menu, ui_units_x=8, keymap=keymap) + return {'FINISHED'} + + +# Studio Light operations +class WM_OT_studiolight_install(Operator): + """Install a user defined studio light""" + bl_idname = "wm.studiolight_install" + bl_label = "Install Custom Studio Light" + + files: CollectionProperty( + name="File Path", + type=OperatorFileListElement, + ) + directory: StringProperty( + subtype='DIR_PATH', + ) + filter_folder: BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_glob: StringProperty( + default="*.png;*.jpg;*.hdr;*.exr", + options={'HIDDEN'}, + ) + orientation: EnumProperty( + items=( + ('MATCAP', "MatCap", ""), + ('WORLD', "World", ""), + ('CAMERA', "Camera", ""), + ) + ) + + def execute(self, context): + import traceback + import shutil + import pathlib + userpref = context.user_preferences + + filepaths = [pathlib.Path(self.directory, e.name) for e in self.files] + path_studiolights = bpy.utils.user_resource('DATAFILES') + + if not path_studiolights: + self.report({'ERROR'}, "Failed to get Studio Light path") + return {'CANCELLED'} + + path_studiolights = pathlib.Path(path_studiolights, "studiolights", self.orientation.lower()) + if not path_studiolights.exists(): + try: + path_studiolights.mkdir(parents=True, exist_ok=True) + except: + traceback.print_exc() + + for filepath in filepaths: + shutil.copy(str(filepath), str(path_studiolights)) + userpref.studio_lights.new(str(path_studiolights.joinpath(filepath.name)), self.orientation) + + # print message + msg = ( + tip_("StudioLight Installed %r into %r") % + (", ".join(str(x.name) for x in self.files), str(path_studiolights)) + ) + print(msg) + self.report({'INFO'}, msg) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +class WM_OT_studiolight_uninstall(Operator): + bl_idname = 'wm.studiolight_uninstall' + bl_label = "Uninstall Studio Light" + index: bpy.props.IntProperty() + + def _remove_path(self, path): + if path.exists(): + path.unlink() + + def execute(self, context): + import pathlib + userpref = context.user_preferences + for studio_light in userpref.studio_lights: + if studio_light.index == self.index: + if len(studio_light.path) > 0: + self._remove_path(pathlib.Path(studio_light.path)) + if len(studio_light.path_irr_cache) > 0: + self._remove_path(pathlib.Path(studio_light.path_irr_cache)) + if len(studio_light.path_sh_cache) > 0: + self._remove_path(pathlib.Path(studio_light.path_sh_cache)) + userpref.studio_lights.remove(studio_light) + return {'FINISHED'} + return {'CANCELLED'} + + +class WM_OT_studiolight_userpref_show(Operator): + """Show light user preferences""" + bl_idname = "wm.studiolight_userpref_show" + bl_label = "" + bl_options = {'INTERNAL'} + + def execute(self, context): + context.user_preferences.active_section = 'LIGHTS' + bpy.ops.screen.userpref_show('INVOKE_DEFAULT') + return {'FINISHED'} + + classes = ( BRUSH_OT_active_index_set, WM_OT_addon_disable, @@ -2350,7 +2534,6 @@ classes = ( WM_OT_app_template_install, WM_OT_appconfig_activate, WM_OT_appconfig_default, - WM_OT_blenderplayer_start, WM_OT_context_collection_boolean_set, WM_OT_context_cycle_array, WM_OT_context_cycle_enum, @@ -2390,5 +2573,12 @@ classes = ( WM_OT_properties_remove, WM_OT_sysinfo, WM_OT_theme_install, + WM_OT_owner_disable, + WM_OT_owner_enable, WM_OT_url_open, + WM_OT_studiolight_install, + WM_OT_studiolight_uninstall, + WM_OT_studiolight_userpref_show, + WM_OT_tool_set_by_name, + WM_OT_toolbar, ) diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index f98074cdf0b..89aed37f055 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -34,15 +34,19 @@ _modules = [ "properties_data_camera", "properties_data_curve", "properties_data_empty", - "properties_data_lamp", + "properties_data_gpencil", + "properties_data_light", "properties_data_lattice", "properties_data_mesh", "properties_data_metaball", "properties_data_modifier", + "properties_data_shaderfx", + "properties_data_lightprobe", "properties_data_speaker", - "properties_game", + "properties_data_workspace", "properties_mask_common", "properties_material", + "properties_material_gpencil", "properties_object", "properties_paint_common", "properties_grease_pencil_common", @@ -57,10 +61,17 @@ _modules = [ "properties_physics_smoke", "properties_physics_softbody", "properties_render", - "properties_render_layer", + "properties_view_layer", "properties_scene", "properties_texture", "properties_world", + + # Generic Space Modules + # + # Depends on DNA_WORKSPACE_TOOL (C define). + "space_toolsystem_common", + "space_toolsystem_toolbar", + "space_clip", "space_console", "space_dopesheet", @@ -68,14 +79,15 @@ _modules = [ "space_graph", "space_image", "space_info", - "space_logic", "space_nla", "space_node", "space_outliner", "space_properties", "space_sequencer", + "space_statusbar", "space_text", "space_time", + "space_topbar", "space_userpref", "space_view3d", "space_view3d_toolbar", diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py index 9782d5a072c..4033d5c2448 100644 --- a/release/scripts/startup/bl_ui/properties_animviz.py +++ b/release/scripts/startup/bl_ui/properties_animviz.py @@ -29,7 +29,7 @@ class MotionPathButtonsPanel: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_label = "Motion Paths" - bl_options = {'DEFAULT_CLOSED'} + # bl_options = {'DEFAULT_CLOSED'} def draw_settings(self, context, avs, mpath, bones=False): layout = self.layout @@ -37,27 +37,26 @@ class MotionPathButtonsPanel: mps = avs.motion_path # Display Range - layout.row().prop(mps, "type", expand=True) + layout.use_property_split = True + layout.row().prop(mps, "type") - split = layout.split() + col = layout.column() - col = split.column() - col.label(text="Display Range:") sub = col.column(align=True) if mps.type == 'CURRENT_FRAME': - sub.prop(mps, "frame_before", text="Before") + sub.prop(mps, "frame_before", text="Frame Range Before") sub.prop(mps, "frame_after", text="After") elif mps.type == 'RANGE': - sub.prop(mps, "frame_start", text="Start") + sub.prop(mps, "frame_start", text="Frame Range Start") sub.prop(mps, "frame_end", text="End") sub.prop(mps, "frame_step", text="Step") - col = split.column() + col = layout.column(align=True) if bones: col.label(text="Cache for Bone:") else: - col.label(text="Cache:") + col.label(text="Cache") if mpath: sub = col.column(align=True) @@ -81,17 +80,15 @@ class MotionPathButtonsPanel: sub.operator("object.paths_calculate", text="Calculate...", icon='OBJECT_DATA') # Display Settings - split = layout.split() - col = split.column() - col.label(text="Show:") + layout.label(text="Display") + + col = layout.column() col.prop(mps, "show_frame_numbers", text="Frame Numbers") if mpath is not None: col.prop(mpath, "lines", text="Lines") col.prop(mpath, "line_thickness", text="Thickness") - col = split.column() - col.label("") col.prop(mps, "show_keyframe_highlight", text="Keyframes") sub = col.column() sub.enabled = mps.show_keyframe_highlight @@ -101,11 +98,11 @@ class MotionPathButtonsPanel: # Customize path if mpath is not None: - row = layout.row(align=True) - row.prop(mpath, "use_custom_color", text="", toggle=True, icon='COLOR') - sub = row.row(align=True) + + col.prop(mpath, "use_custom_color", text="Custom Color") + sub = col.column() sub.enabled = mpath.use_custom_color - sub.prop(mpath, "color", text="") + sub.prop(mpath, "color") # FIXME: this panel still needs to be ported so that it will work correctly with animviz diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index c0fa82946e1..8ea20ada390 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -65,11 +65,6 @@ class DATA_PT_skeleton(ArmatureButtonsPanel, Panel): col.label(text="Protected Layers:") col.prop(arm, "layers_protected", text="") - if context.scene.render.engine == 'BLENDER_GAME': - col = layout.column() - col.label(text="Deform:") - col.prop(arm, "deform_method", expand=True) - class DATA_PT_display(ArmatureButtonsPanel, Panel): bl_label = "Display" @@ -82,15 +77,13 @@ class DATA_PT_display(ArmatureButtonsPanel, Panel): layout.row().prop(arm, "draw_type", expand=True) - split = layout.split() + layout.use_property_split = True - col = split.column() + col = layout.column() col.prop(arm, "show_names", text="Names") col.prop(arm, "show_axes", text="Axes") col.prop(arm, "show_bone_custom_shapes", text="Shapes") - - col = split.column() - col.prop(arm, "show_group_colors", text="Colors") + col.prop(arm, "show_group_colors", text="Group Colors") if ob: col.prop(ob, "show_x_ray", text="X-Ray") col.prop(arm, "use_deform_delay", text="Delay Refresh") @@ -154,7 +147,8 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel): sub = row.row(align=True) sub.operator("pose.group_assign", text="Assign") - sub.operator("pose.group_unassign", text="Remove") # row.operator("pose.bone_group_remove_from", text="Remove") + # row.operator("pose.bone_group_remove_from", text="Remove") + sub.operator("pose.group_unassign", text="Remove") sub = row.row(align=True) sub.operator("pose.group_select", text="Select") @@ -201,7 +195,11 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): if pose_marker_active is not None: col.operator("poselib.pose_remove", icon='ZOOMOUT', text="") - col.operator("poselib.apply_pose", icon='ZOOM_SELECTED', text="").pose_index = poselib.pose_markers.active_index + col.operator( + "poselib.apply_pose", + icon='ZOOM_SELECTED', + text="", + ).pose_index = poselib.pose_markers.active_index col.operator("poselib.action_sanitize", icon='HELP', text="") # XXX: put in menu? @@ -213,6 +211,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): # TODO: this panel will soon be deprecated too class DATA_PT_ghost(ArmatureButtonsPanel, Panel): bl_label = "Ghost" + bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout @@ -221,21 +220,19 @@ class DATA_PT_ghost(ArmatureButtonsPanel, Panel): layout.row().prop(arm, "ghost_type", expand=True) - split = layout.split() + layout.use_property_split = True - col = split.column(align=True) + col = layout.column(align=True) if arm.ghost_type == 'RANGE': - col.prop(arm, "ghost_frame_start", text="Start") + col.prop(arm, "ghost_frame_start", text="Frame Start") col.prop(arm, "ghost_frame_end", text="End") col.prop(arm, "ghost_size", text="Step") elif arm.ghost_type == 'CURRENT_FRAME': - col.prop(arm, "ghost_step", text="Range") + col.prop(arm, "ghost_step", text="Frame Range") col.prop(arm, "ghost_size", text="Step") - col = split.column() - col.label(text="Display:") - col.prop(arm, "show_only_ghost_selected", text="Selected Only") + col.prop(arm, "show_only_ghost_selected", text="Display Selected Only") class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel): @@ -249,6 +246,7 @@ class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object itasc = ob.pose.ik_param @@ -256,34 +254,36 @@ class DATA_PT_iksolver_itasc(ArmatureButtonsPanel, Panel): layout.prop(ob.pose, "ik_solver") if itasc: + layout.use_property_split = False layout.row().prop(itasc, "mode", expand=True) + layout.use_property_split = True simulation = (itasc.mode == 'SIMULATION') if simulation: - layout.label(text="Reiteration:") - layout.row().prop(itasc, "reiteration_method", expand=True) + layout.prop(itasc, "reiteration_method", expand=False) - row = layout.row() - row.active = not simulation or itasc.reiteration_method != 'NEVER' - row.prop(itasc, "precision") - row.prop(itasc, "iterations") + col = layout.column() + col.active = not simulation or itasc.reiteration_method != 'NEVER' + col.prop(itasc, "precision") + col.prop(itasc, "iterations") if simulation: layout.prop(itasc, "use_auto_step") - row = layout.row() + col = layout.column(align=True) if itasc.use_auto_step: - row.prop(itasc, "step_min", text="Min") - row.prop(itasc, "step_max", text="Max") + col.prop(itasc, "step_min", text="Steps Min") + col.prop(itasc, "step_max", text="Max") else: - row.prop(itasc, "step_count") + col.prop(itasc, "step_count", text="Steps") layout.prop(itasc, "solver") if simulation: layout.prop(itasc, "feedback") layout.prop(itasc, "velocity_max") if itasc.solver == 'DLS': - row = layout.row() - row.prop(itasc, "damping_max", text="Damp", slider=True) - row.prop(itasc, "damping_epsilon", text="Eps", slider=True) + col = layout.column() + col.separator() + col.prop(itasc, "damping_max", text="Damping Max", slider=True) + col.prop(itasc, "damping_epsilon", text="Damping Epsilon", slider=True) from .properties_animviz import ( @@ -329,7 +329,7 @@ class DATA_PT_onion_skinning(OnionSkinButtonsPanel): # , Panel): # inherit from class DATA_PT_custom_props_arm(ArmatureButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object.data" _property_type = bpy.types.Armature @@ -341,9 +341,9 @@ classes = ( DATA_MT_bone_group_specials, DATA_PT_bone_groups, DATA_PT_pose_library, + DATA_PT_motion_paths, DATA_PT_ghost, DATA_PT_iksolver_itasc, - DATA_PT_motion_paths, DATA_PT_custom_props_arm, ) diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py index 63b5d4f96fc..6d364ee6539 100644 --- a/release/scripts/startup/bl_ui/properties_data_bone.py +++ b/release/scripts/startup/bl_ui/properties_data_bone.py @@ -62,88 +62,63 @@ class BONE_PT_transform(BoneButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object bone = context.bone + col = layout.column() + if bone and ob: pchan = ob.pose.bones[bone.name] - - row = layout.row() - col = row.column() - col.prop(pchan, "location") col.active = not (bone.parent and bone.use_connect) - col = row.column() + sub = col.row(align=True) + sub.prop(pchan, "location") + sub.prop(pchan, "lock_location", text="") + + col = layout.column() if pchan.rotation_mode == 'QUATERNION': - col.prop(pchan, "rotation_quaternion", text="Rotation") + sub = col.row(align=True) + sub.prop(pchan, "rotation_quaternion", text="Rotation") + subsub = sub.column(align=True) + subsub.prop(pchan, "lock_rotation_w", text="") + subsub.prop(pchan, "lock_rotation", text="") elif pchan.rotation_mode == 'AXIS_ANGLE': # col.label(text="Rotation") #col.prop(pchan, "rotation_angle", text="Angle") #col.prop(pchan, "rotation_axis", text="Axis") - col.prop(pchan, "rotation_axis_angle", text="Rotation") + sub = col.row(align=True) + sub.prop(pchan, "rotation_axis_angle", text="Rotation") + subsub = sub.column(align=True) + subsub.prop(pchan, "lock_rotation_w", text="") + subsub.prop(pchan, "lock_rotation", text="") else: - col.prop(pchan, "rotation_euler", text="Rotation") + sub = col.row(align=True) + sub.prop(pchan, "rotation_euler", text="Rotation") + sub.prop(pchan, "lock_rotation", text="") - row.column().prop(pchan, "scale") + col = layout.column() + sub = col.row(align=True) + sub.prop(pchan, "scale") + sub.prop(pchan, "lock_scale", text="") - layout.prop(pchan, "rotation_mode") + col = layout.column() + col.prop(pchan, "rotation_mode") elif context.edit_bone: bone = context.edit_bone - row = layout.row() - row.column().prop(bone, "head") - row.column().prop(bone, "tail") - - col = row.column() - sub = col.column(align=True) - sub.label(text="Roll:") - sub.prop(bone, "roll", text="") - sub.label() - sub.prop(bone, "lock") - - -class BONE_PT_transform_locks(BoneButtonsPanel, Panel): - bl_label = "Transform Locks" - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - ob = context.object - return ob and ob.mode == 'POSE' and context.bone - - def draw(self, context): - layout = self.layout - - ob = context.object - bone = context.bone - pchan = ob.pose.bones[bone.name] - - split = layout.split(percentage=0.1) - - col = split.column(align=True) - col.label(text="") - col.label(text="X:") - col.label(text="Y:") - col.label(text="Z:") - - col = split.column() - col.active = not (bone.parent and bone.use_connect) - col.prop(pchan, "lock_location", text="Location") - - col = split.column() - col.prop(pchan, "lock_rotation", text="Rotation") - - col = split.column() - col.prop(pchan, "lock_scale", text="Scale") + col = layout.column() + col.prop(bone, "head") + col.prop(bone, "tail") - if pchan.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}: - row = layout.row() - row.prop(pchan, "lock_rotations_4d", text="Lock Rotation") + col = layout.column() + col.prop(bone, "roll") + col.prop(bone, "lock") - sub = row.row() - sub.active = pchan.lock_rotations_4d - sub.prop(pchan, "lock_rotation_w", text="W") + col = layout.column() + col.prop(bone, "tail_radius") + col.prop(bone, "envelope_distance") class BONE_PT_curved(BoneButtonsPanel, Panel): @@ -166,54 +141,52 @@ class BONE_PT_curved(BoneButtonsPanel, Panel): bbone = bone layout = self.layout + layout.use_property_split = True + layout.prop(bone, "bbone_segments", text="Segments") col = layout.column() col.active = bone.bbone_segments > 1 - row = col.row() - sub = row.column(align=True) - sub.label(text="Curve XY Offsets:") - sub.prop(bbone, "bbone_curveinx", text="In X") - sub.prop(bbone, "bbone_curveoutx", text="Out X") - sub.prop(bbone, "bbone_curveiny", text="In Y") - sub.prop(bbone, "bbone_curveouty", text="Out Y") - - sub = row.column(align=True) - sub.label("Roll:") - sub.prop(bbone, "bbone_rollin", text="In") - sub.prop(bbone, "bbone_rollout", text="Out") - sub.prop(bone, "use_endroll_as_inroll") - - row = col.row() - sub = row.column(align=True) - sub.label(text="Scale:") - sub.prop(bbone, "bbone_scalein", text="In") - sub.prop(bbone, "bbone_scaleout", text="Out") - - sub = row.column(align=True) - sub.label("Easing:") - sub.prop(bbone, "bbone_easein", text="In") - sub.prop(bbone, "bbone_easeout", text="Out") + col = layout.column(align=True) + col.prop(bbone, "bbone_curveinx", text="Curve In X") + col.prop(bbone, "bbone_curveiny", text="In Y") + + col = layout.column(align=True) + col.prop(bbone, "bbone_curveoutx", text="Curve Out X") + col.prop(bbone, "bbone_curveouty", text="Out Y") + + col = layout.column(align=True) + col.prop(bbone, "bbone_rollin", text="Roll In") + col.prop(bbone, "bbone_rollout", text="Out") + col.prop(bone, "use_endroll_as_inroll") + + col = layout.column(align=True) + col.prop(bbone, "bbone_scalein", text="Scale In") + col.prop(bbone, "bbone_scaleout", text="Out") + + col = layout.column(align=True) + col.prop(bbone, "bbone_easein", text="Ease In") + col.prop(bbone, "bbone_easeout", text="Out") if pchan: layout.separator() col = layout.column() + col.use_property_split = False col.prop(pchan, "use_bbone_custom_handles") - row = col.row() - row.active = pchan.use_bbone_custom_handles + col = layout.column(align=True) + col.active = pchan.use_bbone_custom_handles + col.use_property_split = True - sub = row.column(align=True) - sub.label(text="In:") - sub.prop_search(pchan, "bbone_custom_handle_start", ob.pose, "bones", text="") - sub.prop(pchan, "use_bbone_relative_start_handle", text="Relative") + sub = col.column() + sub.prop_search(pchan, "bbone_custom_handle_start", ob.pose, "bones", text="Custom Handle Start") + sub.prop_search(pchan, "bbone_custom_handle_end", ob.pose, "bones", text="End") - sub = row.column(align=True) - sub.label(text="Out:") - sub.prop_search(pchan, "bbone_custom_handle_end", ob.pose, "bones", text="") - sub.prop(pchan, "use_bbone_relative_end_handle", text="Relative") + sub = col.column(align=True) + sub.prop(pchan, "use_bbone_relative_start_handle", text="Relative Handle Start") + sub.prop(pchan, "use_bbone_relative_end_handle", text="End") class BONE_PT_relations(BoneButtonsPanel, Panel): @@ -221,6 +194,7 @@ class BONE_PT_relations(BoneButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object bone = context.bone @@ -232,26 +206,22 @@ class BONE_PT_relations(BoneButtonsPanel, Panel): elif bone is None: bone = context.edit_bone - split = layout.split() - - col = split.column() - col.label(text="Layers:") + col = layout.column() + col.use_property_split = False col.prop(bone, "layers", text="") + col.use_property_split = True + col = layout.column() col.separator() - if ob and pchan: - col.label(text="Bone Group:") - col.prop_search(pchan, "bone_group", ob.pose, "bone_groups", text="") - col.label(text="Object Children:") - col.prop(bone, "use_relative_parent") - - col = split.column() - col.label(text="Parent:") if context.bone: - col.prop(bone, "parent", text="") + col.prop(bone, "parent") else: - col.prop_search(bone, "parent", arm, "edit_bones", text="") + col.prop_search(bone, "parent", arm, "edit_bones") + + if ob and pchan: + col.prop(bone, "use_relative_parent") + col.prop_search(pchan, "bone_group", ob.pose, "bone_groups", text="Bone Group") sub = col.column() sub.active = (bone.parent is not None) @@ -274,6 +244,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel): # note. this works ok in edit-mode but isn't # all that useful so disabling for now. layout = self.layout + layout.use_property_split = True ob = context.object bone = context.bone @@ -285,23 +256,20 @@ class BONE_PT_display(BoneButtonsPanel, Panel): bone = context.edit_bone if bone: - split = layout.split() - col = split.column() + col = layout.column() col.prop(bone, "hide", text="Hide") sub = col.column() sub.active = bool(pchan and pchan.custom_shape) sub.prop(bone, "show_wire", text="Wireframe") if pchan: - col = split.column() - - col.label(text="Custom Shape:") - col.prop(pchan, "custom_shape", text="") + col = layout.column() + col.prop(pchan, "custom_shape") if pchan.custom_shape: col.prop(pchan, "use_custom_shape_bone_size", text="Bone Size") col.prop(pchan, "custom_shape_scale", text="Scale") - col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="At") + col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones") class BONE_PT_inverse_kinematics(BoneButtonsPanel, Panel): @@ -315,80 +283,82 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object bone = context.bone pchan = ob.pose.bones[bone.name] - row = layout.row() - active = pchan.is_in_ik_chain - split = layout.split(percentage=0.25) - split.prop(pchan, "lock_ik_x", text="X") - split.active = active - row = split.row() - row.prop(pchan, "ik_stiffness_x", text="Stiffness", slider=True) - row.active = pchan.lock_ik_x is False and active + col = layout.column() + col.prop(pchan, "ik_stretch", slider=True) + col.active = active + + layout.separator() + + col = layout.column(align=True) - split = layout.split(percentage=0.25) - sub = split.row() + col.prop(pchan, "lock_ik_x", text="Lock IK X") + col.prop(pchan, "lock_ik_y", text="Y") + col.prop(pchan, "lock_ik_z", text="Z") - sub.prop(pchan, "use_ik_limit_x", text="Limit") + col = layout.column(align=True) + + sub = col.column(align=True) sub.active = pchan.lock_ik_x is False and active - sub = split.row(align=True) - sub.prop(pchan, "ik_min_x", text="") - sub.prop(pchan, "ik_max_x", text="") - sub.active = pchan.lock_ik_x is False and pchan.use_ik_limit_x and active + sub.prop(pchan, "ik_stiffness_x", text="Stiffness X", slider=True) + sub = col.column(align=True) + sub.active = pchan.lock_ik_y is False and active + sub.prop(pchan, "ik_stiffness_y", text="Y", slider=True) + sub = col.column(align=True) + sub.active = pchan.lock_ik_z is False and active + sub.prop(pchan, "ik_stiffness_z", text="Z", slider=True) + + col = layout.column(align=True) - split = layout.split(percentage=0.25) - split.prop(pchan, "lock_ik_y", text="Y") - split.active = active - row = split.row() - row.prop(pchan, "ik_stiffness_y", text="Stiffness", slider=True) - row.active = pchan.lock_ik_y is False and active + sub = col.column() + sub.active = pchan.lock_ik_x is False and active + sub.prop(pchan, "use_ik_limit_x", text="Limit X") - split = layout.split(percentage=0.25) - sub = split.row() + sub = col.column(align=True) + sub.active = pchan.lock_ik_x is False and pchan.use_ik_limit_x and active + sub.prop(pchan, "ik_min_x", text="Min") + sub.prop(pchan, "ik_max_x", text="Max") + + col.separator() - sub.prop(pchan, "use_ik_limit_y", text="Limit") + sub = col.column() sub.active = pchan.lock_ik_y is False and active + sub.prop(pchan, "use_ik_limit_y", text="Limit Y") - sub = split.row(align=True) - sub.prop(pchan, "ik_min_y", text="") - sub.prop(pchan, "ik_max_y", text="") + sub = col.column(align=True) sub.active = pchan.lock_ik_y is False and pchan.use_ik_limit_y and active + sub.prop(pchan, "ik_min_y", text="Min") + sub.prop(pchan, "ik_max_y", text="Max") - split = layout.split(percentage=0.25) - split.prop(pchan, "lock_ik_z", text="Z") - split.active = active - sub = split.row() - sub.prop(pchan, "ik_stiffness_z", text="Stiffness", slider=True) - sub.active = pchan.lock_ik_z is False and active - - split = layout.split(percentage=0.25) - sub = split.row() + col.separator() - sub.prop(pchan, "use_ik_limit_z", text="Limit") + sub = col.column() sub.active = pchan.lock_ik_z is False and active - sub = split.row(align=True) - sub.prop(pchan, "ik_min_z", text="") - sub.prop(pchan, "ik_max_z", text="") + sub.prop(pchan, "use_ik_limit_z", text="Limit Z") + + sub = col.column(align=True) sub.active = pchan.lock_ik_z is False and pchan.use_ik_limit_z and active + sub.prop(pchan, "ik_min_z", text="Min") + sub.prop(pchan, "ik_max_z", text="Max") - split = layout.split(percentage=0.25) - split.label(text="Stretch:") - sub = split.row() - sub.prop(pchan, "ik_stretch", text="", slider=True) - sub.active = active + col.separator() if ob.pose.ik_solver == 'ITASC': - split = layout.split() - col = split.column() + + col = layout.column() col.prop(pchan, "use_ik_rotation_control", text="Control Rotation") col.active = active - col = split.column() - col.prop(pchan, "ik_rotation_weight", text="Weight", slider=True) + + col = layout.column() + + col.prop(pchan, "ik_rotation_weight", text="IK Rotation Weight", slider=True) col.active = active # not supported yet #row = layout.row() @@ -410,6 +380,7 @@ class BONE_PT_deform(BoneButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True bone = context.bone @@ -418,22 +389,20 @@ class BONE_PT_deform(BoneButtonsPanel, Panel): layout.active = bone.use_deform - row = layout.row() + col = layout.column() + col.prop(bone, "envelope_distance", text="Envelope Distance") + col.prop(bone, "envelope_weight", text="Envelope Weight") + col.prop(bone, "use_envelope_multiply", text="Envelope Multiply") - col = row.column(align=True) - col.label(text="Envelope:") - col.prop(bone, "envelope_distance", text="Distance") - col.prop(bone, "envelope_weight", text="Weight") - col.prop(bone, "use_envelope_multiply", text="Multiply") + col.separator() - col = row.column(align=True) - col.label(text="Envelope Radius:") - col.prop(bone, "head_radius", text="Head") + col = layout.column(align=True) + col.prop(bone, "head_radius", text="Radius Head") col.prop(bone, "tail_radius", text="Tail") class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone @property @@ -448,7 +417,6 @@ class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel): classes = ( BONE_PT_context_bone, BONE_PT_transform, - BONE_PT_transform_locks, BONE_PT_curved, BONE_PT_relations, BONE_PT_display, diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index 14286045704..cc0bde46189 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -20,6 +20,7 @@ import bpy from bpy.types import Panel, Menu from rna_prop_ui import PropertyPanel +from bl_operators.presets import PresetMenu class CameraButtonsPanel: @@ -29,30 +30,30 @@ class CameraButtonsPanel: @classmethod def poll(cls, context): - engine = context.scene.render.engine + engine = context.engine return context.camera and (engine in cls.COMPAT_ENGINES) -class CAMERA_MT_presets(Menu): +class CAMERA_PT_presets(PresetMenu): bl_label = "Camera Presets" preset_subdir = "camera" preset_operator = "script.execute_preset" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - draw = Menu.draw_preset + preset_add_operator = "camera.preset_add" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} -class SAFE_AREAS_MT_presets(Menu): +class SAFE_AREAS_PT_presets(PresetMenu): bl_label = "Camera Presets" preset_subdir = "safe_areas" preset_operator = "script.execute_preset" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - draw = Menu.draw_preset + preset_add_operator = "safe_areas.preset_add" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} class DATA_PT_context_camera(CameraButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -61,83 +62,78 @@ class DATA_PT_context_camera(CameraButtonsPanel, Panel): cam = context.camera space = context.space_data - split = layout.split(percentage=0.65) if ob: - split.template_ID(ob, "data") - split.separator() + layout.template_ID(ob, "data") elif cam: - split.template_ID(space, "pin_id") - split.separator() + layout.template_ID(space, "pin_id") class DATA_PT_lens(CameraButtonsPanel, Panel): bl_label = "Lens" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True cam = context.camera - layout.row().prop(cam, "type", expand=True) + layout.prop(cam, "type") - split = layout.split() + col = layout.column() + col.separator() - col = split.column() if cam.type == 'PERSP': - row = col.row() + col = layout.column() if cam.lens_unit == 'MILLIMETERS': - row.prop(cam, "lens") + col.prop(cam, "lens") elif cam.lens_unit == 'FOV': - row.prop(cam, "angle") - row.prop(cam, "lens_unit", text="") + col.prop(cam, "angle") + col.prop(cam, "lens_unit") elif cam.type == 'ORTHO': col.prop(cam, "ortho_scale") elif cam.type == 'PANO': - engine = context.scene.render.engine + engine = context.engine if engine == 'CYCLES': ccam = cam.cycles - col.prop(ccam, "panorama_type", text="Type") + col.prop(ccam, "panorama_type") if ccam.panorama_type == 'FISHEYE_EQUIDISTANT': col.prop(ccam, "fisheye_fov") elif ccam.panorama_type == 'FISHEYE_EQUISOLID': - row = layout.row() - row.prop(ccam, "fisheye_lens", text="Lens") - row.prop(ccam, "fisheye_fov") + col.prop(ccam, "fisheye_lens", text="Lens") + col.prop(ccam, "fisheye_fov") elif ccam.panorama_type == 'EQUIRECTANGULAR': - row = layout.row() - sub = row.column(align=True) - sub.prop(ccam, "latitude_min") - sub.prop(ccam, "latitude_max") - sub = row.column(align=True) - sub.prop(ccam, "longitude_min") - sub.prop(ccam, "longitude_max") - elif engine == 'BLENDER_RENDER': - row = col.row() + sub = col.column(align=True) + sub.prop(ccam, "latitude_min", text="Latitute Min") + sub.prop(ccam, "latitude_max", text="Max") + sub = col.column(align=True) + sub.prop(ccam, "longitude_min", text="Longiture Min") + sub.prop(ccam, "longitude_max", text="Max") + elif engine in {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}: if cam.lens_unit == 'MILLIMETERS': - row.prop(cam, "lens") + col.prop(cam, "lens") elif cam.lens_unit == 'FOV': - row.prop(cam, "angle") - row.prop(cam, "lens_unit", text="") + col.prop(cam, "angle") + col.prop(cam, "lens_unit") - split = layout.split() + col = layout.column() + col.separator() - col = split.column(align=True) - col.label(text="Shift:") - col.prop(cam, "shift_x", text="X") - col.prop(cam, "shift_y", text="Y") + sub = col.column(align=True) + sub.prop(cam, "shift_x", text="Shift X") + sub.prop(cam, "shift_y", text="Y") - col = split.column(align=True) - col.label(text="Clipping:") - col.prop(cam, "clip_start", text="Start") - col.prop(cam, "clip_end", text="End") + col.separator() + sub = col.column(align=True) + sub.prop(cam, "clip_start", text="Clip Start") + sub.prop(cam, "clip_end", text="End") class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel): bl_label = "Stereoscopy" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -147,6 +143,8 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + render = context.scene.render st = context.camera.stereo cam = context.camera @@ -154,9 +152,9 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel): is_spherical_stereo = cam.type != 'ORTHO' and render.use_spherical_stereo use_spherical_stereo = is_spherical_stereo and st.use_spherical_stereo - col = layout.column() - col.row().prop(st, "convergence_mode", expand=True) + layout.prop(st, "convergence_mode") + col = layout.column() sub = col.column() sub.active = st.convergence_mode != 'PARALLEL' sub.prop(st, "convergence_distance") @@ -165,106 +163,217 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel): if is_spherical_stereo: col.separator() - row = col.row() - row.prop(st, "use_spherical_stereo") - sub = row.row() + col.prop(st, "use_spherical_stereo") + sub = col.column() sub.active = st.use_spherical_stereo sub.prop(st, "use_pole_merge") - row = col.row(align=True) - row.active = st.use_pole_merge - row.prop(st, "pole_merge_angle_from") - row.prop(st, "pole_merge_angle_to") - col.label(text="Pivot:") - row = col.row() - row.active = not use_spherical_stereo - row.prop(st, "pivot", expand=True) + sub = col.column(align=True) + sub.active = st.use_pole_merge + sub.prop(st, "pole_merge_angle_from", text="Pole Merge Angle Start") + sub.prop(st, "pole_merge_angle_to", text="End") + + col = layout.column() + col.active = not use_spherical_stereo + col.separator() + col.prop(st, "pivot") class DATA_PT_camera(CameraButtonsPanel, Panel): bl_label = "Camera" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header_preset(self, context): + CAMERA_PT_presets.draw_panel_header(self.layout) def draw(self, context): layout = self.layout cam = context.camera - row = layout.row(align=True) - - row.menu("CAMERA_MT_presets", text=bpy.types.CAMERA_MT_presets.bl_label) - row.operator("camera.preset_add", text="", icon='ZOOMIN') - row.operator("camera.preset_add", text="", icon='ZOOMOUT').remove_active = True - - layout.label(text="Sensor:") + layout.use_property_split = True - split = layout.split() + col = layout.column() + col.prop(cam, "sensor_fit") - col = split.column(align=True) if cam.sensor_fit == 'AUTO': - col.prop(cam, "sensor_width", text="Size") + col.prop(cam, "sensor_width") else: sub = col.column(align=True) sub.active = cam.sensor_fit == 'HORIZONTAL' sub.prop(cam, "sensor_width", text="Width") + sub = col.column(align=True) sub.active = cam.sensor_fit == 'VERTICAL' sub.prop(cam, "sensor_height", text="Height") - col = split.column(align=True) - col.prop(cam, "sensor_fit", text="") - class DATA_PT_camera_dof(CameraButtonsPanel, Panel): bl_label = "Depth of Field" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout + layout.use_property_split = True cam = context.camera dof_options = cam.gpu_dof - split = layout.split() - - col = split.column() - col.label(text="Focus:") - col.prop(cam, "dof_object", text="") + col = layout.column() + col.prop(cam, "dof_object", text="Focus on Object") sub = col.column() sub.active = (cam.dof_object is None) - sub.prop(cam, "dof_distance", text="Distance") + sub.prop(cam, "dof_distance", text="Focus Distance") - hq_support = dof_options.is_hq_supported - col = split.column(align=True) - col.label("Viewport:") - sub = col.column() - sub.active = hq_support - sub.prop(dof_options, "use_high_quality") - col.prop(dof_options, "fstop") - if dof_options.use_high_quality and hq_support: + +class DATA_PT_camera_dof_aperture(CameraButtonsPanel, Panel): + bl_label = "Aperture" + bl_parent_id = "DATA_PT_camera_dof" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + cam = context.camera + dof_options = cam.gpu_dof + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + if context.engine == 'BLENDER_EEVEE': + col = flow.column() + col.prop(dof_options, "fstop") + col.prop(dof_options, "blades") + + col = flow.column() + col.prop(dof_options, "rotation") + col.prop(dof_options, "ratio") + else: + col = flow.column() + col.label("Viewport") + col.prop(dof_options, "fstop") col.prop(dof_options, "blades") +class DATA_PT_camera_background_image(CameraButtonsPanel, Panel): + bl_label = "Background Images" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + cam = context.camera + + self.layout.prop(cam, "show_background_images", text="") + + def draw(self, context): + layout = self.layout + + cam = context.camera + use_multiview = context.scene.render.use_multiview + + col = layout.column() + col.operator("view3d.background_image_add", text="Add Image") + + for i, bg in enumerate(cam.background_images): + layout.active = cam.show_background_images + box = layout.box() + row = box.row(align=True) + row.prop(bg, "show_expanded", text="", emboss=False) + if bg.source == 'IMAGE' and bg.image: + row.prop(bg.image, "name", text="", emboss=False) + elif bg.source == 'MOVIE_CLIP' and bg.clip: + row.prop(bg.clip, "name", text="", emboss=False) + else: + row.label(text="Not Set") + + if bg.show_background_image: + row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_OFF') + else: + row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_ON') + + row.operator("view3d.background_image_remove", text="", emboss=False, icon='X').index = i + + if bg.show_expanded: + row = box.row() + row.prop(bg, "source", expand=True) + + has_bg = False + if bg.source == 'IMAGE': + row = box.row() + row.template_ID(bg, "image", open="image.open") + if bg.image is not None: + box.template_image(bg, "image", bg.image_user, compact=True) + has_bg = True + + if use_multiview and bg.view_axis in {'CAMERA', 'ALL'}: + box.prop(bg.image, "use_multiview") + + column = box.column() + column.active = bg.image.use_multiview + + column.label(text="Views Format:") + column.row().prop(bg.image, "views_format", expand=True) + + sub = column.box() + sub.active = bg.image.views_format == 'STEREO_3D' + sub.template_image_stereo_3d(bg.image.stereo_3d_format) + + elif bg.source == 'MOVIE_CLIP': + box.prop(bg, "use_camera_clip") + + column = box.column() + column.active = not bg.use_camera_clip + column.template_ID(bg, "clip", open="clip.open") + + if bg.clip: + column.template_movieclip(bg, "clip", compact=True) + + if bg.use_camera_clip or bg.clip: + has_bg = True + + column = box.column() + column.active = has_bg + column.prop(bg.clip_user, "proxy_render_size", text="") + column.prop(bg.clip_user, "use_render_undistorted") + + if has_bg: + col = box.column() + col.prop(bg, "alpha", slider=True) + col.row().prop(bg, "draw_depth", expand=True) + + col.row().prop(bg, "frame_method", expand=True) + + box = col.box() + row = box.row() + row.prop(bg, "offset") + + row = box.row() + row.prop(bg, "use_flip_x") + row.prop(bg, "use_flip_y") + + row = box.row() + row.prop(bg, "rotation") + row.prop(bg, "scale") + + class DATA_PT_camera_display(CameraButtonsPanel, Panel): - bl_label = "Display" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_label = "Viewport Display" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True cam = context.camera split = layout.split() + split.label() + split.prop_menu_enum(cam, "show_guide") - col = split.column() - col.prop(cam, "show_limits", text="Limits") - col.prop(cam, "show_mist", text="Mist") + col = layout.column(align=True) - col.prop(cam, "show_sensor", text="Sensor") - col.prop(cam, "show_name", text="Name") - - col = split.column() - col.prop_menu_enum(cam, "show_guide") col.separator() col.prop(cam, "draw_size", text="Size") col.separator() @@ -273,17 +382,27 @@ class DATA_PT_camera_display(CameraButtonsPanel, Panel): sub.active = cam.show_passepartout sub.prop(cam, "passepartout_alpha", text="Alpha", slider=True) + col.separator() + + col.prop(cam, "show_limits", text="Limits") + col.prop(cam, "show_mist", text="Mist") + col.prop(cam, "show_sensor", text="Sensor") + col.prop(cam, "show_name", text="Name") + class DATA_PT_camera_safe_areas(CameraButtonsPanel, Panel): bl_label = "Safe Areas" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): cam = context.camera self.layout.prop(cam, "show_safe_areas", text="") + def draw_header_preset(self, context): + SAFE_AREAS_PT_presets.draw_panel_header(self.layout) + def draw(self, context): layout = self.layout safe_data = context.scene.safe_areas @@ -293,7 +412,7 @@ class DATA_PT_camera_safe_areas(CameraButtonsPanel, Panel): class DATA_PT_custom_props_camera(CameraButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object.data" _property_type = bpy.types.Camera @@ -302,39 +421,37 @@ def draw_display_safe_settings(layout, safe_data, settings): show_safe_areas = settings.show_safe_areas show_safe_center = settings.show_safe_center - split = layout.split() + layout.use_property_split = True - col = split.column() - row = col.row(align=True) - row.menu("SAFE_AREAS_MT_presets", text=bpy.types.SAFE_AREAS_MT_presets.bl_label) - row.operator("safe_areas.preset_add", text="", icon='ZOOMIN') - row.operator("safe_areas.preset_add", text="", icon='ZOOMOUT').remove_active = True + col = layout.column() + col.active = show_safe_areas - col = split.column() - col.prop(settings, "show_safe_center", text="Center-Cut Safe Areas") + sub = col.column() + sub.prop(safe_data, "title", slider=True) + sub.prop(safe_data, "action", slider=True) - split = layout.split() - col = split.column() - col.active = show_safe_areas - col.prop(safe_data, "title", slider=True) - col.prop(safe_data, "action", slider=True) + col.separator() + + col.prop(settings, "show_safe_center", text="Center-Cut Safe Areas") - col = split.column() - col.active = show_safe_areas and show_safe_center - col.prop(safe_data, "title_center", slider=True) - col.prop(safe_data, "action_center", slider=True) + sub = col.column() + sub.active = show_safe_areas and show_safe_center + sub.prop(safe_data, "title_center", slider=True) + sub.prop(safe_data, "action_center", slider=True) classes = ( - CAMERA_MT_presets, - SAFE_AREAS_MT_presets, + CAMERA_PT_presets, + SAFE_AREAS_PT_presets, DATA_PT_context_camera, DATA_PT_lens, DATA_PT_camera, DATA_PT_camera_stereoscopy, DATA_PT_camera_dof, + DATA_PT_camera_dof_aperture, DATA_PT_camera_display, DATA_PT_camera_safe_areas, + DATA_PT_camera_background_image, DATA_PT_custom_props_camera, ) diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index f57156c1bae..4002568fb7d 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -93,63 +93,63 @@ class DATA_PT_shape_curve(CurveButtonsPanel, Panel): row = layout.row() row.prop(curve, "dimensions", expand=True) - split = layout.split() + layout.use_property_split = True + + col = layout.column() + sub = col.column(align=True) + sub.prop(curve, "resolution_u", text="Resolution Preview U") + if is_surf: + sub.prop(curve, "resolution_v", text="V") - col = split.column() - col.label(text="Resolution:") sub = col.column(align=True) - sub.prop(curve, "resolution_u", text="Preview U") sub.prop(curve, "render_resolution_u", text="Render U") + if is_surf: + sub.prop(curve, "render_resolution_v", text="V") + col.separator() + if is_curve: - col.label(text="Twisting:") - col.prop(curve, "twist_mode", text="") + col.prop(curve, "twist_mode") col.prop(curve, "twist_smooth", text="Smooth") elif is_text: - col.label(text="Display:") col.prop(curve, "use_fast_edit", text="Fast Editing") - col = split.column() - - if is_surf: - sub = col.column() - sub.label(text="") - sub = col.column(align=True) - sub.prop(curve, "resolution_v", text="Preview V") - sub.prop(curve, "render_resolution_v", text="Render V") - if is_curve or is_text: - col.label(text="Fill:") + col = layout.column() + col.separator() + sub = col.column() sub.active = (curve.dimensions == '2D' or (curve.bevel_object is None and curve.dimensions == '3D')) - sub.prop(curve, "fill_mode", text="") + sub.prop(curve, "fill_mode") col.prop(curve, "use_fill_deform") if is_curve: - col.label(text="Path/Curve-Deform:") + col = layout.column() + col.separator() + sub = col.column() - subsub = sub.row() - subsub.prop(curve, "use_radius") - subsub.prop(curve, "use_stretch") + sub.prop(curve, "use_radius") + sub.prop(curve, "use_stretch") sub.prop(curve, "use_deform_bounds") class DATA_PT_curve_texture_space(CurveButtonsPanel, Panel): bl_label = "Texture Space" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True curve = context.curve - row = layout.row() - row.prop(curve, "use_auto_texspace") - row.prop(curve, "use_uv_as_generated") + col = layout.column() + col.prop(curve, "use_uv_as_generated") + col.prop(curve, "use_auto_texspace") - row = layout.row() - row.column().prop(curve, "texspace_location", text="Location") - row.column().prop(curve, "texspace_size", text="Size") + col = layout.column() + col.prop(curve, "texspace_location") + col.prop(curve, "texspace_size") layout.operator("curve.match_texture_space") @@ -163,29 +163,51 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True curve = context.curve - split = layout.split() - - col = split.column() - col.label(text="Modification:") + col = layout.column() col.prop(curve, "offset") - col.prop(curve, "extrude") - col.label(text="Taper Object:") - col.prop(curve, "taper_object", text="") - col = split.column() - col.label(text="Bevel:") - col.prop(curve, "bevel_depth", text="Depth") - col.prop(curve, "bevel_resolution", text="Resolution") - col.label(text="Bevel Object:") - col.prop(curve, "bevel_object", text="") + sub = col.column() + sub.active = (curve.bevel_object is None) + sub.prop(curve, "extrude") + + col.prop(curve, "taper_object") + + sub = col.column() + sub.active = curve.taper_object is not None + sub.prop(curve, "use_map_taper") + + +class DATA_PT_geometry_curve_bevel(CurveButtonsPanelCurve, Panel): + bl_label = "Bevel" + bl_parent_id = "DATA_PT_geometry_curve" + + @classmethod + def poll(cls, context): + return (type(context.curve) in {Curve, TextCurve}) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + curve = context.curve + + col = layout.column() + sub = col.column() + sub.active = (curve.bevel_object is None) + sub.prop(curve, "bevel_depth", text="Depth") + sub.prop(curve, "bevel_resolution", text="Resolution") + + col.prop(curve, "bevel_object", text="Object") + + sub = col.column() + sub.active = curve.bevel_object is not None + sub.prop(curve, "use_fill_caps") if type(curve) is not TextCurve: - col = layout.column(align=True) - row = col.row() - row.label(text="Bevel Factor:") col = layout.column() col.active = ( @@ -193,20 +215,13 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel): (curve.extrude > 0.0) or (curve.bevel_object is not None) ) - row = col.row(align=True) - row.prop(curve, "bevel_factor_mapping_start", text="") - row.prop(curve, "bevel_factor_start", text="Start") - row = col.row(align=True) - row.prop(curve, "bevel_factor_mapping_end", text="") - row.prop(curve, "bevel_factor_end", text="End") + sub = col.column(align=True) + sub.prop(curve, "bevel_factor_start", text="Bevel Start") + sub.prop(curve, "bevel_factor_end", text="End") - row = layout.row() - sub = row.row() - sub.active = curve.taper_object is not None - sub.prop(curve, "use_map_taper") - sub = row.row() - sub.active = curve.bevel_object is not None - sub.prop(curve, "use_fill_caps") + sub = col.column(align=True) + sub.prop(curve, "bevel_factor_mapping_start", text="Bevel Mapping Start") + sub.prop(curve, "bevel_factor_mapping_end", text="End") class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel): @@ -219,6 +234,7 @@ class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True curve = context.curve @@ -229,8 +245,9 @@ class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel): col.prop(curve, "eval_time") # these are for paths only - row = layout.row() - row.prop(curve, "use_path_follow") + col.separator() + + col.prop(curve, "use_path_follow") class DATA_PT_active_spline(CurveButtonsPanelActive, Panel): @@ -238,65 +255,64 @@ class DATA_PT_active_spline(CurveButtonsPanelActive, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True curve = context.curve act_spline = curve.splines.active is_surf = type(curve) is SurfaceCurve is_poly = (act_spline.type == 'POLY') - split = layout.split() + col = layout.column() if is_poly: # These settings are below but its easier to have # polys set aside since they use so few settings - row = layout.row() - row.label(text="Cyclic:") - row.prop(act_spline, "use_cyclic_u", text="U") - layout.prop(act_spline, "use_smooth") + col.prop(act_spline, "use_cyclic_u") + col.prop(act_spline, "use_smooth") else: - col = split.column() - col.label(text="Cyclic:") - if act_spline.type == 'NURBS': - col.label(text="Bezier:") - col.label(text="Endpoint:") - col.label(text="Order:") - col.label(text="Resolution:") - - col = split.column() - col.prop(act_spline, "use_cyclic_u", text="U") + sub = col.column(align=True) + sub.prop(act_spline, "use_cyclic_u") + if is_surf: + sub.prop(act_spline, "use_cyclic_v", text="V") if act_spline.type == 'NURBS': - sub = col.column() + sub = col.column(align=True) # sub.active = (not act_spline.use_cyclic_u) - sub.prop(act_spline, "use_bezier_u", text="U") - sub.prop(act_spline, "use_endpoint_u", text="U") + sub.prop(act_spline, "use_bezier_u", text="Bezier U") - sub = col.column() - sub.prop(act_spline, "order_u", text="U") - col.prop(act_spline, "resolution_u", text="U") + if is_surf: + subsub = sub.column() + subsub.active = (not act_spline.use_cyclic_v) + subsub.prop(act_spline, "use_bezier_v", text="V") - if is_surf: - col = split.column() - col.prop(act_spline, "use_cyclic_v", text="V") + sub = col.column(align=True) + sub.prop(act_spline, "use_endpoint_u", text="Endpoint U") - # its a surface, assume its a nurbs - sub = col.column() - sub.active = (not act_spline.use_cyclic_v) - sub.prop(act_spline, "use_bezier_v", text="V") - sub.prop(act_spline, "use_endpoint_v", text="V") - sub = col.column() - sub.prop(act_spline, "order_v", text="V") + if is_surf: + subsub = sub.column() + subsub.active = (not act_spline.use_cyclic_v) + subsub.prop(act_spline, "use_endpoint_v", text="V") + + sub = col.column(align=True) + sub.prop(act_spline, "order_u", text="Order U") + + if is_surf: + sub.prop(act_spline, "order_v", text="V") + + sub = col.column(align=True) + sub.prop(act_spline, "resolution_u", text="Resolution U") + if is_surf: sub.prop(act_spline, "resolution_v", text="V") if act_spline.type == 'BEZIER': - col = layout.column() - col.label(text="Interpolation:") + + col.separator() sub = col.column() sub.active = (curve.dimensions == '3D') - sub.prop(act_spline, "tilt_interpolation", text="Tilt") + sub.prop(act_spline, "tilt_interpolation", text="Interpolation Tilt") col.prop(act_spline, "radius_interpolation", text="Radius") @@ -325,42 +341,46 @@ class DATA_PT_font(CurveButtonsPanelText, Panel): row.label(text="Bold & Italic") row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink") - # layout.prop(text, "font") + layout.separator() - split = layout.split() + row = layout.row(align=True) + row.prop(char, "use_bold", toggle=True) + row.prop(char, "use_italic", toggle=True) + row.prop(char, "use_underline", toggle=True) + row.prop(char, "use_small_caps", toggle=True) + + +class DATA_PT_font_transform(CurveButtonsPanelText, Panel): + bl_label = "Transform" + bl_parent_id = "DATA_PT_font" + + def draw(self, context): + layout = self.layout + + text = context.curve + char = context.curve.edit_format + + layout.use_property_split = True + + col = layout.column() + + col.separator() - col = split.column() col.prop(text, "size", text="Size") - col = split.column() col.prop(text, "shear") - split = layout.split() - - col = split.column() - col.label(text="Object Font:") - col.prop(text, "family", text="") + col.separator() - col = split.column() - col.label(text="Text on Curve:") - col.prop(text, "follow_curve", text="") + col.prop(text, "family") + col.prop(text, "follow_curve") - split = layout.split() + col.separator() - col = split.column() sub = col.column(align=True) - sub.label(text="Underline:") - sub.prop(text, "underline_position", text="Position") - sub.prop(text, "underline_height", text="Thickness") - - col = split.column() - col.label(text="Character:") - col.prop(char, "use_bold") - col.prop(char, "use_italic") - col.prop(char, "use_underline") + sub.prop(text, "underline_position", text="Underline Position") + sub.prop(text, "underline_height", text="Underline Thickness") - row = layout.row() - row.prop(text, "small_caps_scale", text="Small Caps") - row.prop(char, "use_small_caps") + col.prop(text, "small_caps_scale", text="Small Caps Scale") class DATA_PT_paragraph(CurveButtonsPanelText, Panel): @@ -371,23 +391,40 @@ class DATA_PT_paragraph(CurveButtonsPanelText, Panel): text = context.curve - layout.label(text="Horizontal Alignment:") - layout.row().prop(text, "align_x", expand=True) - layout.label(text="Vertical Alignment:") +class DATA_PT_paragraph_alignment(CurveButtonsPanelText, Panel): + bl_parent_id = "DATA_PT_paragraph" + bl_label = "Alignment" + + def draw(self, context): + layout = self.layout + layout.use_property_split = False + + text = context.curve + + layout.row().prop(text, "align_x", expand=True) layout.row().prop(text, "align_y", expand=True) - split = layout.split() - col = split.column(align=True) - col.label(text="Spacing:") - col.prop(text, "space_character", text="Letter") - col.prop(text, "space_word", text="Word") - col.prop(text, "space_line", text="Line") +class DATA_PT_paragraph_spacing(CurveButtonsPanelText, Panel): + bl_parent_id = "DATA_PT_paragraph" + bl_label = "Spacing" - col = split.column(align=True) - col.label(text="Offset:") - col.prop(text, "offset_x", text="X") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + text = context.curve + + col = layout.column(align=True) + col.prop(text, "space_character", text="Character Spacing") + col.prop(text, "space_word", text="Word Spacing") + col.prop(text, "space_line", text="Line Spacing") + + layout.separator() + + col = layout.column(align=True) + col.prop(text, "offset_x", text="Offset X") col.prop(text, "offset_y", text="Y") @@ -399,10 +436,7 @@ class DATA_PT_text_boxes(CurveButtonsPanelText, Panel): text = context.curve - split = layout.split() - col = split.column() - col.operator("font.textbox_add", icon='ZOOMIN') - col = split.column() + layout.operator("font.textbox_add", icon='ZOOMIN') for i, box in enumerate(text.text_boxes): @@ -410,25 +444,22 @@ class DATA_PT_text_boxes(CurveButtonsPanelText, Panel): row = boxy.row() - split = row.split() - - col = split.column(align=True) - - col.label(text="Dimensions:") - col.prop(box, "width", text="Width") - col.prop(box, "height", text="Height") + col = row.column() + col.use_property_split = True - col = split.column(align=True) + sub = col.column(align=True) + sub.prop(box, "width", text="Size X") + sub.prop(box, "height", text="Y") - col.label(text="Offset:") - col.prop(box, "x", text="X") - col.prop(box, "y", text="Y") + sub = col.column(align=True) + sub.prop(box, "x", text="Offset X") + sub.prop(box, "y", text="Y") row.operator("font.textbox_remove", text="", icon='X', emboss=False).index = i class DATA_PT_custom_props_curve(CurveButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object.data" _property_type = bpy.types.Curve @@ -438,10 +469,14 @@ classes = ( DATA_PT_shape_curve, DATA_PT_curve_texture_space, DATA_PT_geometry_curve, + DATA_PT_geometry_curve_bevel, DATA_PT_pathanim, DATA_PT_active_spline, DATA_PT_font, + DATA_PT_font_transform, DATA_PT_paragraph, + DATA_PT_paragraph_alignment, + DATA_PT_paragraph_spacing, DATA_PT_text_boxes, DATA_PT_custom_props_curve, ) diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py index c66ff87ecbd..ab12d0f5c5f 100644 --- a/release/scripts/startup/bl_ui/properties_data_empty.py +++ b/release/scripts/startup/bl_ui/properties_data_empty.py @@ -36,10 +36,11 @@ class DATA_PT_empty(DataButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object - layout.prop(ob, "empty_draw_type", text="Display") + layout.prop(ob, "empty_draw_type", text="Display As") if ob.empty_draw_type == 'IMAGE': layout.template_ID(ob, "data", open="image.open", unlink="object.unlink_data") @@ -49,9 +50,11 @@ class DATA_PT_empty(DataButtonsPanel, Panel): row = layout.row(align=True) layout.prop(ob, "color", text="Transparency", index=3, slider=True) - row = layout.row(align=True) - row.prop(ob, "empty_image_offset", text="Offset X", index=0) - row.prop(ob, "empty_image_offset", text="Offset Y", index=1) + col = layout.column(align=True) + col.prop(ob, "empty_image_offset", text="Offset X", index=0) + col.prop(ob, "empty_image_offset", text="Y", index=1) + + layout.separator() layout.prop(ob, "empty_draw_size", text="Size") diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py new file mode 100644 index 00000000000..90dc86a20bb --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -0,0 +1,404 @@ +# ##### 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> +import bpy +from bpy.types import Menu, Panel, UIList +from rna_prop_ui import PropertyPanel +from .properties_grease_pencil_common import ( + GreasePencilDataPanel, + GreasePencilOnionPanel, +) + +############################### +# Base-Classes (for shared stuff - e.g. poll, attributes, etc.) + + +class DataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + return context.object and context.object.type == 'GPENCIL' + + +class LayerDataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + return (context.object and + context.object.type == 'GPENCIL' and + context.active_gpencil_layer) + + +############################### +# GP Object Properties Panels and Helper Classes + +class DATA_PT_gpencil(DataButtonsPanel, Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + + def draw(self, context): + layout = self.layout + + # Grease Pencil data selector + gpd_owner = context.gpencil_data_owner + gpd = context.gpencil_data + + layout.template_ID(gpd_owner, "data") + + +class GPENCIL_UL_layer(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.GPencilLayer) + gpl = item + gpd = context.gpencil_data + + if self.layout_type in {'DEFAULT', 'COMPACT'}: + if gpl.lock: + layout.active = False + + row = layout.row(align=True) + if gpl.is_parented: + icon = 'BONE_DATA' + else: + icon = 'BLANK1' + + row.label(text="", icon=icon) + row.prop(gpl, "info", text="", emboss=False) + + row = layout.row(align=True) + row.prop(gpl, "lock", text="", emboss=False) + row.prop(gpl, "hide", text="", emboss=False) + row.prop(gpl, "unlock_color", text="", emboss=False) + if gpl.use_onion_skinning is False: + icon = 'GHOST_DISABLED' + else: + icon = 'GHOST_ENABLED' + subrow = row.row(align=True) + subrow.prop(gpl, "use_onion_skinning", text="", icon=icon, emboss=False) + subrow.active = gpd.use_onion_skinning + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class GPENCIL_MT_layer_specials(Menu): + bl_label = "Layer" + + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon + + layout.separator() + + layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All") + layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True + + layout.separator() + + layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All") + layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All") + + layout.separator() + + layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down") + + +class DATA_PT_gpencil_datapanel(Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Layers" + + @classmethod + def poll(cls, context): + if context.gpencil_data is None: + return False + + ob = context.object + if ob is not None and ob.type == 'GPENCIL': + return True + + return False + + @staticmethod + def draw(self, context): + layout = self.layout + #layout.use_property_split = True + layout.use_property_decorate = False + + gpd = context.gpencil_data + + # Grease Pencil data... + if (gpd is None) or (not gpd.layers): + layout.operator("gpencil.layer_add", text="New Layer") + else: + self.draw_layers(context, layout, gpd) + + def draw_layers(self, context, layout, gpd): + row = layout.row() + + col = row.column() + if len(gpd.layers) >= 2: + layer_rows = 5 + else: + layer_rows = 2 + col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows) + + col = row.column() + + sub = col.column(align=True) + sub.operator("gpencil.layer_add", icon='ZOOMIN', text="") + sub.operator("gpencil.layer_remove", icon='ZOOMOUT', text="") + + gpl = context.active_gpencil_layer + if gpl: + sub.menu("GPENCIL_MT_layer_specials", 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_OFF', text="").affect_visibility = True + + row = layout.row(align=True) + if gpl: + row.prop(gpl, "opacity", text="Opacity", slider=True) + + +class DATA_PT_gpencil_layer_optionpanel(LayerDataButtonsPanel, Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Adjustments" + bl_parent_id = 'DATA_PT_gpencil_datapanel' + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + gpl = context.active_gpencil_layer + layout.active = not gpl.lock + + # Layer options + # Offsets - Color Tint + layout.enabled = not gpl.lock + col = layout.column(align=True) + col.prop(gpl, "tint_color") + col.prop(gpl, "tint_factor", text="Factor", slider=True) + + # Offsets - Thickness + col = layout.row(align=True) + col.prop(gpl, "line_change", text="Stroke Thickness") + + +class DATA_PT_gpencil_parentpanel(LayerDataButtonsPanel, Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Relations" + bl_parent_id = 'DATA_PT_gpencil_datapanel' + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + gpl = context.active_gpencil_layer + col = layout.column() + col.active = not gpl.lock + col.prop(gpl, "parent") + col.prop(gpl, "parent_type", text="Type") + parent = gpl.parent + + if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE': + col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone") + + +class DATA_PT_gpencil_onionpanel(Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Onion Skinning" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return bool(context.active_gpencil_layer) + + @staticmethod + def draw_header(self, context): + self.layout.prop(context.gpencil_data, "use_onion_skinning", text="") + + def draw(self, context): + gpd = context.gpencil_data + + layout = self.layout + layout.use_property_split = True + layout.enabled = gpd.use_onion_skinning + + GreasePencilOnionPanel.draw_settings(layout, gpd) + + +class GPENCIL_MT_gpencil_vertex_group(Menu): + bl_label = "GP Vertex Groups" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'EXEC_AREA' + layout.operator("object.vertex_group_add") + + ob = context.active_object + if ob.vertex_groups.active: + layout.separator() + + layout.operator("gpencil.vertex_group_assign", text="Assign to Active Group") + layout.operator("gpencil.vertex_group_remove_from", text="Remove from Active Group") + + layout.separator() + layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group") + layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False + layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True + + layout.separator() + layout.operator("gpencil.vertex_group_select", text="Select Points") + layout.operator("gpencil.vertex_group_deselect", text="Deselect Points") + + +class GPENCIL_UL_vgroups(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + vgroup = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon) + # icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED' + # layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False) + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class DATA_PT_gpencil_vertexpanel(DataButtonsPanel, Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + bl_label = "Vertex Groups" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + + ob = context.object + group = ob.vertex_groups.active + + rows = 2 + if group: + rows = 4 + + row = layout.row() + row.template_list("GPENCIL_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows) + + col = row.column(align=True) + col.operator("object.vertex_group_add", icon='ZOOMIN', text="") + col.operator("object.vertex_group_remove", icon='ZOOMOUT', text="").all = False + + if ob.vertex_groups: + row = layout.row() + + sub = row.row(align=True) + sub.operator("gpencil.vertex_group_assign", text="Assign") + sub.operator("gpencil.vertex_group_remove_from", text="Remove") + + sub = row.row(align=True) + sub.operator("gpencil.vertex_group_select", text="Select") + sub.operator("gpencil.vertex_group_deselect", text="Deselect") + + layout.prop(context.tool_settings, "vertex_group_weight", text="Weight") + + +class DATA_PT_gpencil_display(DataButtonsPanel, Panel): + bl_label = "Viewport Display" + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + + gpd = context.gpencil_data + gpl = context.active_gpencil_layer + + layout.prop(gpd, "xray_mode", text="Depth Ordering") + layout.prop(gpd, "edit_line_color", text="Edit Line Color") + layout.prop(ob, "empty_draw_size", text="Marker Size") + + col = layout.column(align=True) + col.prop(gpd, "show_constant_thickness") + sub = col.column() + sub.active = not gpd.show_constant_thickness + sub.prop(gpd, "pixfactor", text="Thickness Scale") + + if gpl: + layout.prop(gpd, "show_stroke_direction", text="Show Stroke Directions") + + +class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel): + _context_path = "object.data" + _property_type = bpy.types.GreasePencil + +############################### + + +classes = ( + DATA_PT_gpencil, + DATA_PT_gpencil_datapanel, + DATA_PT_gpencil_onionpanel, + DATA_PT_gpencil_layer_optionpanel, + DATA_PT_gpencil_parentpanel, + DATA_PT_gpencil_vertexpanel, + DATA_PT_gpencil_display, + DATA_PT_custom_props_gpencil, + + GPENCIL_UL_layer, + GPENCIL_UL_vgroups, + + GPENCIL_MT_layer_specials, + GPENCIL_MT_gpencil_vertex_group, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py deleted file mode 100644 index f9394139b42..00000000000 --- a/release/scripts/startup/bl_ui/properties_data_lamp.py +++ /dev/null @@ -1,414 +0,0 @@ -# ##### 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> -import bpy -from bpy.types import Menu, Panel -from rna_prop_ui import PropertyPanel - - -class LAMP_MT_sunsky_presets(Menu): - bl_label = "Sun & Sky Presets" - preset_subdir = "sunsky" - preset_operator = "script.execute_preset" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - draw = Menu.draw_preset - - -class DataButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "data" - - @classmethod - def poll(cls, context): - engine = context.scene.render.engine - return context.lamp and (engine in cls.COMPAT_ENGINES) - - -class DATA_PT_context_lamp(DataButtonsPanel, Panel): - bl_label = "" - bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - ob = context.object - lamp = context.lamp - space = context.space_data - - split = layout.split(percentage=0.65) - - texture_count = len(lamp.texture_slots.keys()) - - if ob: - split.template_ID(ob, "data") - elif lamp: - split.template_ID(space, "pin_id") - - if texture_count != 0: - split.label(text=str(texture_count), icon='TEXTURE') - - -class DATA_PT_preview(DataButtonsPanel, Panel): - bl_label = "Preview" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - def draw(self, context): - self.layout.template_preview(context.lamp) - - -class DATA_PT_lamp(DataButtonsPanel, Panel): - bl_label = "Lamp" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - lamp = context.lamp - - layout.row().prop(lamp, "type", expand=True) - - split = layout.split() - - col = split.column() - sub = col.column() - sub.prop(lamp, "color", text="") - sub.prop(lamp, "energy") - - if lamp.type in {'POINT', 'SPOT'}: - sub.label(text="Falloff:") - sub.prop(lamp, "falloff_type", text="") - sub.prop(lamp, "distance") - - if lamp.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED': - col.label(text="Attenuation Factors:") - sub = col.column(align=True) - sub.prop(lamp, "linear_attenuation", slider=True, text="Linear") - sub.prop(lamp, "quadratic_attenuation", slider=True, text="Quadratic") - - elif lamp.falloff_type == 'INVERSE_COEFFICIENTS': - col.label(text="Inverse Coefficients:") - sub = col.column(align=True) - sub.prop(lamp, "constant_coefficient", text="Constant") - sub.prop(lamp, "linear_coefficient", text="Linear") - sub.prop(lamp, "quadratic_coefficient", text="Quadratic") - - col.prop(lamp, "use_sphere") - - if lamp.type == 'AREA': - col.prop(lamp, "distance") - col.prop(lamp, "gamma") - - col = split.column() - col.prop(lamp, "use_negative") - col.prop(lamp, "use_own_layer", text="This Layer Only") - col.prop(lamp, "use_specular") - col.prop(lamp, "use_diffuse") - - -class DATA_PT_sunsky(DataButtonsPanel, Panel): - bl_label = "Sky & Atmosphere" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - lamp = context.lamp - engine = context.scene.render.engine - return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - lamp = context.lamp.sky - - row = layout.row(align=True) - row.prop(lamp, "use_sky") - row.menu("LAMP_MT_sunsky_presets", text=bpy.types.LAMP_MT_sunsky_presets.bl_label) - row.operator("lamp.sunsky_preset_add", text="", icon='ZOOMIN') - row.operator("lamp.sunsky_preset_add", text="", icon='ZOOMOUT').remove_active = True - - row = layout.row() - row.active = lamp.use_sky or lamp.use_atmosphere - row.prop(lamp, "atmosphere_turbidity", text="Turbidity") - - split = layout.split() - - col = split.column() - col.active = lamp.use_sky - col.label(text="Blending:") - sub = col.column() - sub.prop(lamp, "sky_blend_type", text="") - sub.prop(lamp, "sky_blend", text="Factor") - - col.label(text="Color Space:") - sub = col.column() - sub.row().prop(lamp, "sky_color_space", expand=True) - sub.prop(lamp, "sky_exposure", text="Exposure") - - col = split.column() - col.active = lamp.use_sky - col.label(text="Horizon:") - sub = col.column() - sub.prop(lamp, "horizon_brightness", text="Brightness") - sub.prop(lamp, "spread", text="Spread") - - col.label(text="Sun:") - sub = col.column() - sub.prop(lamp, "sun_brightness", text="Brightness") - sub.prop(lamp, "sun_size", text="Size") - sub.prop(lamp, "backscattered_light", slider=True, text="Back Light") - - layout.separator() - - layout.prop(lamp, "use_atmosphere") - - split = layout.split() - - col = split.column() - col.active = lamp.use_atmosphere - col.label(text="Intensity:") - col.prop(lamp, "sun_intensity", text="Sun") - col.prop(lamp, "atmosphere_distance_factor", text="Distance") - - col = split.column() - col.active = lamp.use_atmosphere - col.label(text="Scattering:") - sub = col.column(align=True) - sub.prop(lamp, "atmosphere_inscattering", slider=True, text="Inscattering") - sub.prop(lamp, "atmosphere_extinction", slider=True, text="Extinction") - - -class DATA_PT_shadow(DataButtonsPanel, Panel): - bl_label = "Shadow" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - lamp = context.lamp - engine = context.scene.render.engine - return (lamp and lamp.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - lamp = context.lamp - - layout.row().prop(lamp, "shadow_method", expand=True) - - if lamp.shadow_method == 'NOSHADOW' and lamp.type == 'AREA': - split = layout.split() - - col = split.column() - col.label(text="Form Factor Sampling:") - - sub = col.row(align=True) - - if lamp.shape == 'SQUARE': - sub.prop(lamp, "shadow_ray_samples_x", text="Samples") - elif lamp.shape == 'RECTANGLE': - sub.prop(lamp, "shadow_ray_samples_x", text="Samples X") - sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y") - - if lamp.shadow_method != 'NOSHADOW': - split = layout.split() - - col = split.column() - col.prop(lamp, "shadow_color", text="") - - col = split.column() - col.prop(lamp, "use_shadow_layer", text="This Layer Only") - col.prop(lamp, "use_only_shadow") - - if lamp.shadow_method == 'RAY_SHADOW': - split = layout.split() - - col = split.column() - col.label(text="Sampling:") - - if lamp.type in {'POINT', 'SUN', 'SPOT'}: - sub = col.row() - - sub.prop(lamp, "shadow_ray_samples", text="Samples") - sub.prop(lamp, "shadow_soft_size", text="Soft Size") - - elif lamp.type == 'AREA': - sub = col.row(align=True) - - if lamp.shape == 'SQUARE': - sub.prop(lamp, "shadow_ray_samples_x", text="Samples") - elif lamp.shape == 'RECTANGLE': - sub.prop(lamp, "shadow_ray_samples_x", text="Samples X") - sub.prop(lamp, "shadow_ray_samples_y", text="Samples Y") - - col.row().prop(lamp, "shadow_ray_sample_method", expand=True) - - if lamp.shadow_ray_sample_method == 'ADAPTIVE_QMC': - layout.prop(lamp, "shadow_adaptive_threshold", text="Threshold") - - if lamp.type == 'AREA' and lamp.shadow_ray_sample_method == 'CONSTANT_JITTERED': - row = layout.row() - row.prop(lamp, "use_umbra") - row.prop(lamp, "use_dither") - row.prop(lamp, "use_jitter") - - elif lamp.shadow_method == 'BUFFER_SHADOW': - col = layout.column() - col.label(text="Buffer Type:") - col.row().prop(lamp, "shadow_buffer_type", expand=True) - - if lamp.shadow_buffer_type in {'REGULAR', 'HALFWAY', 'DEEP'}: - split = layout.split() - - col = split.column() - col.label(text="Filter Type:") - col.prop(lamp, "shadow_filter_type", text="") - sub = col.column(align=True) - sub.prop(lamp, "shadow_buffer_soft", text="Soft") - sub.prop(lamp, "shadow_buffer_bias", text="Bias") - - col = split.column() - col.label(text="Sample Buffers:") - col.prop(lamp, "shadow_sample_buffers", text="") - sub = col.column(align=True) - sub.prop(lamp, "shadow_buffer_size", text="Size") - sub.prop(lamp, "shadow_buffer_samples", text="Samples") - if lamp.shadow_buffer_type == 'DEEP': - col.prop(lamp, "compression_threshold") - - elif lamp.shadow_buffer_type == 'IRREGULAR': - layout.prop(lamp, "shadow_buffer_bias", text="Bias") - - split = layout.split() - - col = split.column() - col.prop(lamp, "use_auto_clip_start", text="Autoclip Start") - sub = col.column() - sub.active = not lamp.use_auto_clip_start - sub.prop(lamp, "shadow_buffer_clip_start", text="Clip Start") - - col = split.column() - col.prop(lamp, "use_auto_clip_end", text="Autoclip End") - sub = col.column() - sub.active = not lamp.use_auto_clip_end - sub.prop(lamp, "shadow_buffer_clip_end", text=" Clip End") - - -class DATA_PT_area(DataButtonsPanel, Panel): - bl_label = "Area Shape" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - lamp = context.lamp - engine = context.scene.render.engine - return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - lamp = context.lamp - - col = layout.column() - col.row().prop(lamp, "shape", expand=True) - sub = col.row(align=True) - - if lamp.shape == 'SQUARE': - sub.prop(lamp, "size") - elif lamp.shape == 'RECTANGLE': - sub.prop(lamp, "size", text="Size X") - sub.prop(lamp, "size_y", text="Size Y") - - -class DATA_PT_spot(DataButtonsPanel, Panel): - bl_label = "Spot Shape" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - lamp = context.lamp - engine = context.scene.render.engine - return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - lamp = context.lamp - - split = layout.split() - - col = split.column() - sub = col.column() - sub.prop(lamp, "spot_size", text="Size") - sub.prop(lamp, "spot_blend", text="Blend", slider=True) - col.prop(lamp, "use_square") - col.prop(lamp, "show_cone") - - col = split.column() - - col.active = (lamp.shadow_method != 'BUFFER_SHADOW' or lamp.shadow_buffer_type != 'DEEP') - col.prop(lamp, "use_halo") - sub = col.column(align=True) - sub.active = lamp.use_halo - sub.prop(lamp, "halo_intensity", text="Intensity") - if lamp.shadow_method == 'BUFFER_SHADOW': - sub.prop(lamp, "halo_step", text="Step") - - -class DATA_PT_falloff_curve(DataButtonsPanel, Panel): - bl_label = "Falloff Curve" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - lamp = context.lamp - engine = context.scene.render.engine - - return (lamp and lamp.type in {'POINT', 'SPOT'} and lamp.falloff_type == 'CUSTOM_CURVE') and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - lamp = context.lamp - - self.layout.template_curve_mapping(lamp, "falloff_curve", use_negative_slope=True) - - -class DATA_PT_custom_props_lamp(DataButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - _context_path = "object.data" - _property_type = bpy.types.Lamp - - -classes = ( - LAMP_MT_sunsky_presets, - DATA_PT_context_lamp, - DATA_PT_preview, - DATA_PT_lamp, - DATA_PT_sunsky, - DATA_PT_shadow, - DATA_PT_area, - DATA_PT_spot, - DATA_PT_falloff_curve, - DATA_PT_custom_props_lamp, -) - -if __name__ == "__main__": # only for live edit. - from bpy.utils import register_class - for cls in classes: - register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_lattice.py b/release/scripts/startup/bl_ui/properties_data_lattice.py index 4b3fd48c195..9aa8a4dee64 100644 --- a/release/scripts/startup/bl_ui/properties_data_lattice.py +++ b/release/scripts/startup/bl_ui/properties_data_lattice.py @@ -57,28 +57,35 @@ class DATA_PT_lattice(DataButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True lat = context.lattice - row = layout.row() - row.prop(lat, "points_u") - row.prop(lat, "interpolation_type_u", text="") + col = layout.column() - row = layout.row() - row.prop(lat, "points_v") - row.prop(lat, "interpolation_type_v", text="") + sub = col.column(align=True) + sub.prop(lat, "points_u", text="Resolution U") + sub.prop(lat, "points_v", text="V") + sub.prop(lat, "points_w", text="W") - row = layout.row() - row.prop(lat, "points_w") - row.prop(lat, "interpolation_type_w", text="") + col.separator() - row = layout.row() - row.prop(lat, "use_outside") - row.prop_search(lat, "vertex_group", context.object, "vertex_groups", text="") + sub = col.column(align=True) + sub.prop(lat, "interpolation_type_u", text="Interpolation U") + sub.prop(lat, "interpolation_type_v", text="V") + sub.prop(lat, "interpolation_type_w", text="W") + + col.separator() + + col.prop(lat, "use_outside") + + col.separator() + + col.prop_search(lat, "vertex_group", context.object, "vertex_groups") class DATA_PT_custom_props_lattice(DataButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object.data" _property_type = bpy.types.Lattice diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py new file mode 100644 index 00000000000..f5c985f2abe --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_light.py @@ -0,0 +1,295 @@ +# ##### 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> +import bpy +from bpy.types import Menu, Panel +from rna_prop_ui import PropertyPanel + + +class DataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + engine = context.engine + return context.light and (engine in cls.COMPAT_ENGINES) + + +class DATA_PT_context_light(DataButtonsPanel, Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + + ob = context.object + light = context.light + space = context.space_data + + if ob: + layout.template_ID(ob, "data") + elif light: + layout.template_ID(space, "pin_id") + + +class DATA_PT_preview(DataButtonsPanel, Panel): + bl_label = "Preview" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + def draw(self, context): + self.layout.template_preview(context.light) + + +class DATA_PT_light(DataButtonsPanel, Panel): + bl_label = "Light" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + + light = context.light + + layout.row().prop(light, "type", expand=True) + + +class DATA_PT_EEVEE_light(DataButtonsPanel, Panel): + bl_label = "Light" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + light = context.light + + layout.row().prop(light, "type", expand=True) + + layout.use_property_split = True + + col = layout.column() + col.prop(light, "color") + col.prop(light, "energy") + col.prop(light, "specular_factor", text="Specular") + + col.separator() + + if light.type in {'POINT', 'SPOT', 'SUN'}: + col.prop(light, "shadow_soft_size", text="Radius") + elif light.type == 'AREA': + col.prop(light, "shape") + + sub = col.column(align=True) + + if light.shape in {'SQUARE', 'DISK'}: + sub.prop(light, "size") + elif light.shape in {'RECTANGLE', 'ELLIPSE'}: + sub.prop(light, "size", text="Size X") + sub.prop(light, "size_y", text="Y") + + +class DATA_PT_EEVEE_shadow(DataButtonsPanel, Panel): + bl_label = "Shadow" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + light = context.light + engine = context.engine + return (light and light.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and (engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + light = context.light + self.layout.prop(light, "use_shadow", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + light = context.light + + layout.active = light.use_shadow + + col = layout.column() + sub = col.column(align=True) + sub.prop(light, "shadow_buffer_clip_start", text="Clip Start") + sub.prop(light, "shadow_buffer_clip_end", text="End") + + col.prop(light, "shadow_buffer_soft", text="Softness") + + col.separator() + + col.prop(light, "shadow_buffer_bias", text="Bias") + col.prop(light, "shadow_buffer_exp", text="Exponent") + col.prop(light, "shadow_buffer_bleed_bias", text="Bleed Bias") + + +class DATA_PT_EEVEE_shadow_cascaded_shadow_map(DataButtonsPanel, Panel): + bl_label = "Cascaded Shadow Map" + bl_parent_id = "DATA_PT_EEVEE_shadow" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + light = context.light + engine = context.engine + + return (light and light.type == 'SUN') and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + light = context.light + layout.use_property_split = True + + col = layout.column() + + col.prop(light, "shadow_cascade_count", text="Count") + col.prop(light, "shadow_cascade_fade", text="Fade") + + col.prop(light, "shadow_cascade_max_distance", text="Max Distance") + col.prop(light, "shadow_cascade_exponent", text="Distribution") + + +class DATA_PT_EEVEE_shadow_contact(DataButtonsPanel, Panel): + bl_label = "Contact Shadows" + bl_parent_id = "DATA_PT_EEVEE_shadow" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + light = context.light + engine = context.engine + return (light and light.type in {'POINT', 'SUN', 'SPOT', 'AREA'}) and (engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + light = context.light + + layout = self.layout + layout.active = light.use_shadow + layout.prop(light, "use_contact_shadow", text="") + + def draw(self, context): + layout = self.layout + light = context.light + layout.use_property_split = True + + col = layout.column() + col.active = light.use_shadow and light.use_contact_shadow + + col.prop(light, "contact_shadow_distance", text="Distance") + col.prop(light, "contact_shadow_soft_size", text="Softness") + col.prop(light, "contact_shadow_bias", text="Bias") + col.prop(light, "contact_shadow_thickness", text="Thickness") + + +class DATA_PT_area(DataButtonsPanel, Panel): + bl_label = "Area Shape" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + light = context.light + engine = context.engine + return (light and light.type == 'AREA') and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + light = context.light + + col = layout.column() + col.row().prop(light, "shape", expand=True) + sub = col.row(align=True) + + if light.shape in {'SQUARE', 'DISK'}: + sub.prop(light, "size") + elif light.shape in {'RECTANGLE', 'ELLIPSE'}: + sub.prop(light, "size", text="Size X") + sub.prop(light, "size_y", text="Size Y") + + +class DATA_PT_spot(DataButtonsPanel, Panel): + bl_label = "Spot Shape" + bl_parent_id = "DATA_PT_EEVEE_light" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + light = context.light + engine = context.engine + return (light and light.type == 'SPOT') and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + light = context.light + + col = layout.column() + + col.prop(light, "spot_size", text="Size") + col.prop(light, "spot_blend", text="Blend", slider=True) + + col.prop(light, "show_cone") + + +class DATA_PT_falloff_curve(DataButtonsPanel, Panel): + bl_label = "Falloff Curve" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + light = context.light + engine = context.engine + + return (light and light.type in {'POINT', 'SPOT'} and light.falloff_type == 'CUSTOM_CURVE') and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + light = context.light + + self.layout.template_curve_mapping(light, "falloff_curve", use_negative_slope=True) + + +class DATA_PT_custom_props_light(DataButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + _context_path = "object.data" + _property_type = bpy.types.Light + + +classes = ( + DATA_PT_context_light, + DATA_PT_preview, + DATA_PT_light, + DATA_PT_EEVEE_light, + DATA_PT_EEVEE_shadow, + DATA_PT_EEVEE_shadow_contact, + DATA_PT_EEVEE_shadow_cascaded_shadow_map, + DATA_PT_area, + DATA_PT_spot, + DATA_PT_falloff_curve, + DATA_PT_custom_props_light, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_lightprobe.py b/release/scripts/startup/bl_ui/properties_data_lightprobe.py new file mode 100644 index 00000000000..5924a796b65 --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_lightprobe.py @@ -0,0 +1,182 @@ +# ##### 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> +import bpy +from bpy.types import Panel + + +class DataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + engine = context.engine + return context.lightprobe and (engine in cls.COMPAT_ENGINES) + + +class DATA_PT_context_lightprobe(DataButtonsPanel, Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + + ob = context.object + probe = context.lightprobe + space = context.space_data + + if ob: + layout.template_ID(ob, "data") + elif probe: + layout.template_ID(space, "pin_id") + + +class DATA_PT_lightprobe(DataButtonsPanel, Panel): + bl_label = "Probe" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + probe = context.lightprobe + +# layout.prop(probe, "type") + + if probe.type == 'GRID': + col = layout.column() + col.prop(probe, "influence_distance", "Distance") + col.prop(probe, "falloff") + col.prop(probe, "intensity") + + col.separator() + + col.prop(probe, "grid_resolution_x", text="Resolution X") + col.prop(probe, "grid_resolution_y", text="Y") + col.prop(probe, "grid_resolution_z", text="Z") + + elif probe.type == 'PLANAR': + col = layout.column() + col.prop(probe, "influence_distance", "Distance") + col.prop(probe, "falloff") + else: + col = layout.column() + col.prop(probe, "influence_type") + + if probe.influence_type == 'ELIPSOID': + col.prop(probe, "influence_distance", "Radius") + else: + col.prop(probe, "influence_distance", "Size") + + col.prop(probe, "falloff") + col.prop(probe, "intensity") + + col = layout.column() + sub = col.column() + sub.prop(probe, "clip_start", text="Clipping Start") + + if probe.type != "PLANAR": + sub.prop(probe, "clip_end", text="End") + + if probe.type == 'GRID': + col.separator() + col.label("Visibility") + col.prop(probe, "visibility_buffer_bias", "Bias") + col.prop(probe, "visibility_bleed_bias", "Bleed Bias") + col.prop(probe, "visibility_blur", "Blur") + + col.separator() + + row = col.row(align=True) + row.prop(probe, "visibility_collection") + row.prop(probe, "invert_visibility_collection", text="", icon='ARROW_LEFTRIGHT') + + +class DATA_PT_lightprobe_parallax(DataButtonsPanel, Panel): + bl_label = "Custom Parallax" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + engine = context.engine + return context.lightprobe and context.lightprobe.type == 'CUBEMAP' and (engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + probe = context.lightprobe + self.layout.prop(probe, "use_custom_parallax", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + probe = context.lightprobe + + col = layout.column() + col.active = probe.use_custom_parallax + + col.prop(probe, "parallax_type") + + if probe.parallax_type == 'ELIPSOID': + col.prop(probe, "parallax_distance", "Radius") + else: + col.prop(probe, "parallax_distance", "Size") + + +class DATA_PT_lightprobe_display(DataButtonsPanel, Panel): + bl_label = "Display" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + probe = context.lightprobe + + col = layout.column() + + if probe.type == 'PLANAR': + col.prop(ob, "empty_draw_size", text="Arrow Size") + col.prop(probe, "show_data") + + if probe.type in {'GRID', 'CUBEMAP'}: + col.prop(probe, "show_influence") + col.prop(probe, "show_clip") + + if probe.type == 'CUBEMAP': + sub = col.column() + sub.active = probe.use_custom_parallax + sub.prop(probe, "show_parallax") + + +classes = ( + DATA_PT_context_lightprobe, + DATA_PT_lightprobe, + DATA_PT_lightprobe_parallax, + DATA_PT_lightprobe_display, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 2ab9aa2e93f..f096ff83957 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -24,7 +24,6 @@ from rna_prop_ui import PropertyPanel class MESH_MT_vertex_group_specials(Menu): bl_label = "Vertex Group Specials" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} def draw(self, context): layout = self.layout @@ -48,7 +47,6 @@ class MESH_MT_vertex_group_specials(Menu): class MESH_MT_shape_key_specials(Menu): bl_label = "Shape Key Specials" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} def draw(self, context): layout = self.layout @@ -76,6 +74,17 @@ class MESH_UL_vgroups(UIList): layout.label(text="", icon_value=icon) +class MESH_UL_fmaps(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.FaceMap)) + fmap = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.prop(fmap, "name", text="", emboss=False, icon_value=icon) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + class MESH_UL_shape_keys(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): # assert(isinstance(item, bpy.types.ShapeKey)) @@ -119,14 +128,14 @@ class MeshButtonsPanel: @classmethod def poll(cls, context): - engine = context.scene.render.engine + engine = context.engine return context.mesh and (engine in cls.COMPAT_ENGINES) class DATA_PT_context_mesh(MeshButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -143,31 +152,32 @@ class DATA_PT_context_mesh(MeshButtonsPanel, Panel): class DATA_PT_normals(MeshButtonsPanel, Panel): bl_label = "Normals" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True mesh = context.mesh - split = layout.split() + col = layout.column() + col.prop(mesh, "show_double_sided") - col = split.column() col.prop(mesh, "use_auto_smooth") sub = col.column() sub.active = mesh.use_auto_smooth and not mesh.has_custom_normals sub.prop(mesh, "auto_smooth_angle", text="Angle") - split.prop(mesh, "show_double_sided") - class DATA_PT_texture_space(MeshButtonsPanel, Panel): bl_label = "Texture Space" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True mesh = context.mesh @@ -176,18 +186,18 @@ class DATA_PT_texture_space(MeshButtonsPanel, Panel): layout.separator() layout.prop(mesh, "use_auto_texspace") - row = layout.row() - row.column().prop(mesh, "texspace_location", text="Location") - row.column().prop(mesh, "texspace_size", text="Size") + + layout.prop(mesh, "texspace_location", text="Location") + layout.prop(mesh, "texspace_size", text="Size") class DATA_PT_vertex_groups(MeshButtonsPanel, Panel): bl_label = "Vertex Groups" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - engine = context.scene.render.engine + engine = context.engine obj = context.object return (obj and obj.type in {'MESH', 'LATTICE'} and (engine in cls.COMPAT_ENGINES)) @@ -228,13 +238,56 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel): layout.prop(context.tool_settings, "vertex_group_weight", text="Weight") +class DATA_PT_face_maps(MeshButtonsPanel, Panel): + bl_label = "Face Maps" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.type == 'MESH') + + def draw(self, context): + layout = self.layout + + ob = context.object + facemap = ob.face_maps.active + + rows = 2 + if facemap: + rows = 4 + + row = layout.row() + row.template_list("MESH_UL_fmaps", "", ob, "face_maps", ob.face_maps, "active_index", rows=rows) + + col = row.column(align=True) + col.operator("object.face_map_add", icon='ZOOMIN', text="") + col.operator("object.face_map_remove", icon='ZOOMOUT', text="") + if facemap: + col.separator() + col.operator("object.face_map_move", icon='TRIA_UP', text="").direction = 'UP' + col.operator("object.face_map_move", icon='TRIA_DOWN', text="").direction = 'DOWN' + + if ob.face_maps and (ob.mode == 'EDIT' and ob.type == 'MESH'): + row = layout.row() + + sub = row.row(align=True) + sub.operator("object.face_map_assign", text="Assign") + sub.operator("object.face_map_remove_from", text="Remove") + + sub = row.row(align=True) + sub.operator("object.face_map_select", text="Select") + sub.operator("object.face_map_deselect", text="Deselect") + + class DATA_PT_shape_keys(MeshButtonsPanel, Panel): bl_label = "Shape Keys" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - engine = context.scene.render.engine + engine = context.engine obj = context.object return (obj and obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'} and (engine in cls.COMPAT_ENGINES)) @@ -300,19 +353,16 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel): row.active = enable_edit_value row.prop(kb, "value") - split = layout.split() + layout.use_property_split = True - col = split.column(align=True) - col.active = enable_edit_value - col.label(text="Range:") - col.prop(kb, "slider_min", text="Min") - col.prop(kb, "slider_max", text="Max") + col = layout.column() + sub.active = enable_edit_value + sub = col.column(align=True) + sub.prop(kb, "slider_min", text="Range Min") + sub.prop(kb, "slider_max", text="Max") - col = split.column(align=True) - col.active = enable_edit_value - col.label(text="Blend:") - col.prop_search(kb, "vertex_group", ob, "vertex_groups", text="") - col.prop_search(kb, "relative_key", key, "key_blocks", text="") + col.prop_search(kb, "vertex_group", ob, "vertex_groups", text="Vertex Group") + col.prop_search(kb, "relative_key", key, "key_blocks", text="Relative To") else: layout.prop(kb, "interpolation") @@ -323,7 +373,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel): class DATA_PT_uv_texture(MeshButtonsPanel, Panel): bl_label = "UV Maps" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -333,7 +383,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel): row = layout.row() col = row.column() - col.template_list("MESH_UL_uvmaps_vcols", "uvmaps", me, "uv_textures", me.uv_textures, "active_index", rows=1) + col.template_list("MESH_UL_uvmaps_vcols", "uvmaps", me, "uv_layers", me.uv_layers, "active_index", rows=1) col = row.column(align=True) col.operator("mesh.uv_texture_add", icon='ZOOMIN', text="") @@ -342,7 +392,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel): class DATA_PT_vertex_colors(MeshButtonsPanel, Panel): bl_label = "Vertex Colors" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -362,10 +412,11 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel): class DATA_PT_customdata(MeshButtonsPanel, Panel): bl_label = "Geometry Data" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True obj = context.object me = context.mesh @@ -388,7 +439,7 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel): class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object.data" _property_type = bpy.types.Mesh @@ -397,15 +448,17 @@ classes = ( MESH_MT_vertex_group_specials, MESH_MT_shape_key_specials, MESH_UL_vgroups, + MESH_UL_fmaps, MESH_UL_shape_keys, MESH_UL_uvmaps_vcols, DATA_PT_context_mesh, - DATA_PT_normals, - DATA_PT_texture_space, DATA_PT_vertex_groups, DATA_PT_shape_keys, DATA_PT_uv_texture, DATA_PT_vertex_colors, + DATA_PT_face_maps, + DATA_PT_normals, + DATA_PT_texture_space, DATA_PT_customdata, DATA_PT_custom_props_mesh, ) diff --git a/release/scripts/startup/bl_ui/properties_data_metaball.py b/release/scripts/startup/bl_ui/properties_data_metaball.py index dd62c4523b1..75015a57f5f 100644 --- a/release/scripts/startup/bl_ui/properties_data_metaball.py +++ b/release/scripts/startup/bl_ui/properties_data_metaball.py @@ -54,40 +54,36 @@ class DATA_PT_metaball(DataButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True mball = context.meta_ball - split = layout.split() - - col = split.column() + col = layout.column() col.label(text="Resolution:") sub = col.column(align=True) - sub.prop(mball, "resolution", text="View") + sub.prop(mball, "resolution", text="Resolution View") sub.prop(mball, "render_resolution", text="Render") - col = split.column() - col.label(text="Settings:") col.prop(mball, "threshold", text="Threshold") - - layout.label(text="Update:") - layout.row().prop(mball, "update_method", expand=True) + col.prop(mball, "update_method") class DATA_PT_mball_texture_space(DataButtonsPanel, Panel): bl_label = "Texture Space" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True mball = context.meta_ball layout.prop(mball, "use_auto_texspace") - row = layout.row() - row.column().prop(mball, "texspace_location", text="Location") - row.column().prop(mball, "texspace_size", text="Size") + col = layout.column() + col.prop(mball, "texspace_location") + col.prop(mball, "texspace_size") class DATA_PT_metaball_element(DataButtonsPanel, Panel): @@ -99,39 +95,37 @@ class DATA_PT_metaball_element(DataButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True metaelem = context.meta_ball.elements.active - layout.prop(metaelem, "type") + col = layout.column() - split = layout.split() + col.prop(metaelem, "type") + + col.separator() - col = split.column(align=True) - col.label(text="Settings:") col.prop(metaelem, "stiffness", text="Stiffness") col.prop(metaelem, "use_negative", text="Negative") col.prop(metaelem, "hide", text="Hide") - col = split.column(align=True) + sub = col.column(align=True) if metaelem.type in {'CUBE', 'ELLIPSOID'}: - col.label(text="Size:") - col.prop(metaelem, "size_x", text="X") - col.prop(metaelem, "size_y", text="Y") - col.prop(metaelem, "size_z", text="Z") + sub.prop(metaelem, "size_x", text="Size X") + sub.prop(metaelem, "size_y", text="Y") + sub.prop(metaelem, "size_z", text="Z") elif metaelem.type == 'TUBE': - col.label(text="Size:") - col.prop(metaelem, "size_x", text="X") + sub.prop(metaelem, "size_x", text="Size X") elif metaelem.type == 'PLANE': - col.label(text="Size:") - col.prop(metaelem, "size_x", text="X") - col.prop(metaelem, "size_y", text="Y") + sub.prop(metaelem, "size_x", text="Size X") + sub.prop(metaelem, "size_y", text="Y") class DATA_PT_custom_props_metaball(DataButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object.data" _property_type = bpy.types.MetaBall diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 1a80a160ea5..93e789bbd19 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -32,6 +32,11 @@ class ModifierButtonsPanel: class DATA_PT_modifiers(ModifierButtonsPanel, Panel): bl_label = "Modifiers" + @classmethod + def poll(cls, context): + ob = context.object + return ob and ob.type != 'GPENCIL' + def draw(self, context): layout = self.layout @@ -140,6 +145,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "use_only_vertices") col.prop(md, "use_clamp_overlap") col.prop(md, "loop_slide") + col.prop(md, "mark_seam") + col.prop(md, "mark_sharp") layout.label(text="Limit Method:") layout.row().prop(md, "limit_method", expand=True) @@ -152,6 +159,12 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): layout.label(text="Width Method:") layout.row().prop(md, "offset_type", expand=True) + layout.label(text="Normal Mode") + layout.row().prop(md, "hnmode", expand=True) + layout.prop(md, "hn_strength") + layout.prop(md, "set_wn_strength") + + def BOOLEAN(self, layout, ob, md): split = layout.split() @@ -327,8 +340,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): row.prop(md, "delimit") layout_info = layout - layout_info.label(text=iface_("Face Count: {:,}".format(md.face_count)), - translate=False) + layout_info.label( + text=iface_("Face Count: {:,}".format(md.face_count)), + translate=False, + ) def DISPLACE(self, layout, ob, md): has_texture = (md.texture is not None) @@ -357,7 +372,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "texture_coords_object", text="") elif md.texture_coords == 'UV' and ob.type == 'MESH': col.label(text="UV Map:") - col.prop_search(md, "uv_layer", ob.data, "uv_textures", text="") + col.prop_search(md, "uv_layer", ob.data, "uv_layers", text="") layout.separator() @@ -389,7 +404,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): sub.active = bool(md.vertex_group) sub.prop(md, "protect") col.label(text="Particle UV") - col.prop_search(md, "particle_uv", ob.data, "uv_textures", text="") + col.prop_search(md, "particle_uv", ob.data, "uv_layers", text="") col = split.column() col.prop(md, "use_edge_cut") @@ -953,7 +968,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() scene = context.scene - engine = scene.render.engine + engine = context.engine show_adaptive_options = ( engine == 'CYCLES' and md == ob.modifiers[-1] and scene.cycles.feature_set == 'EXPERIMENTAL' @@ -1016,18 +1031,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): def UV_PROJECT(self, layout, ob, md): split = layout.split() - - col = split.column() - col.label(text="Image:") - col.prop(md, "image", text="") - col = split.column() - col.label(text="UV Map:") - col.prop_search(md, "uv_layer", ob.data, "uv_textures", text="") + col.prop_search(md, "uv_layer", ob.data, "uv_layers") + col.separator() - split = layout.split() - col = split.column() - col.prop(md, "use_image_override") col.prop(md, "projector_count", text="Projectors") for proj in md.projectors: col.prop(proj, "object", text="") @@ -1081,7 +1088,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.texture_coords == 'OBJECT': layout.prop(md, "texture_coords_object", text="Object") elif md.texture_coords == 'UV' and ob.type == 'MESH': - layout.prop_search(md, "uv_layer", ob.data, "uv_textures") + layout.prop_search(md, "uv_layer", ob.data, "uv_layers") def WAVE(self, layout, ob, md): split = layout.split() @@ -1127,7 +1134,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.template_ID(md, "texture", new="texture.new") layout.prop(md, "texture_coords") if md.texture_coords == 'UV' and ob.type == 'MESH': - layout.prop_search(md, "uv_layer", ob.data, "uv_textures") + layout.prop_search(md, "uv_layer", ob.data, "uv_layers") elif md.texture_coords == 'OBJECT': layout.prop(md, "texture_coords_object") @@ -1194,7 +1201,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.mask_tex_mapping == 'OBJECT': layout.prop(md, "mask_tex_map_object", text="Object") elif md.mask_tex_mapping == 'UV' and ob.type == 'MESH': - layout.prop_search(md, "mask_tex_uv_layer", ob.data, "uv_textures") + layout.prop_search(md, "mask_tex_uv_layer", ob.data, "uv_layers") def VERTEX_WEIGHT_EDIT(self, layout, ob, md): split = layout.split() @@ -1363,7 +1370,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.label(text="UV Map:") - col.prop_search(md, "uv_layer", ob.data, "uv_textures", text="") + col.prop_search(md, "uv_layer", ob.data, "uv_layers", text="") def WIREFRAME(self, layout, ob, md): has_vgroup = bool(md.vertex_group) @@ -1570,9 +1577,468 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.rest_source == 'BIND': layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind") + def WEIGHTED_NORMAL(self, layout, ob, md): + layout.label("Weighting Mode:") + split = layout.split(align=True) + col = split.column(align=True) + col.prop(md, "mode", text="") + col.prop(md, "weight", text="Weight") + col.prop(md, "keep_sharp") + + col = split.column(align=True) + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.active = bool(md.vertex_group) + row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT') + col.prop(md, "thresh", text="Threshold") + col.prop(md, "face_influence") + + +class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): + bl_label = "Modifiers" + + @classmethod + def poll(cls, context): + ob = context.object + return ob and ob.type == 'GPENCIL' + + def draw(self, context): + layout = self.layout + + ob = context.object + + layout.operator_menu_enum("object.gpencil_modifier_add", "type") + + 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(self, md.type)(box, ob, md) + + # the mt.type enum is (ab)used for a lookup on function names + # ...to avoid lengthy if statements + # so each type must have a function here. + + def GP_NOISE(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + row = col.row(align=True) + row.prop(md, "factor") + row.prop(md, "random", text="", icon="TIME", toggle=True) + row = col.row() + row.enabled = md.random + row.prop(md, "step") + col.prop(md, "full_stroke") + col.prop(md, "move_extreme") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row(align=True) + row.label("Affect:") + row = layout.row(align=True) + row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True) + row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True) + row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True) + row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True) + + def GP_SMOOTH(self, layout, ob, md): + gpd = ob.data + row = layout.row(align=False) + row.prop(md, "factor") + row.prop(md, "step") + + split = layout.split() + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col = split.column() + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row(align=True) + row.label("Affect:") + row = layout.row(align=True) + row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True) + row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True) + row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True) + row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True) + + def GP_SUBDIV(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + row = col.row(align=True) + row.prop(md, "level") + row.prop(md, "simple", text="", icon="PARTICLE_POINT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + def GP_SIMPLIFY(self, layout, ob, md): + gpd = ob.data + + row = layout.row() + row.prop(md, "mode") + + split = layout.split() + + col = split.column() + col.label("Settings:") + row = col.row(align=True) + row.enabled = md.mode == 'FIXED' + row.prop(md, "step") + + row = col.row(align=True) + row.enabled = not md.mode == 'FIXED' + row.prop(md, "factor") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + def GP_THICK(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + row = col.row(align=True) + row.prop(md, "thickness") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + col.prop(md, "normalize_thickness") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + if not md.normalize_thickness: + split = layout.split() + col = split.column() + col.prop(md, "use_custom_curve") + + if md.use_custom_curve: + col.template_curve_mapping(md, "curve") + + def GP_TINT(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.prop(md, "color") + col.prop(md, "factor") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row() + row.prop(md, "create_materials") + row.prop(md, "modify_color") + + + def GP_COLOR(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label("Color:") + col.prop(md, "hue", text="H") + col.prop(md, "saturation", text="S") + col.prop(md, "value", text="V") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row() + row.prop(md, "create_materials") + row.prop(md, "modify_color") + + def GP_OPACITY(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label("Opacity:") + col.prop(md, "factor") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row() + row.prop(md, "create_materials") + row.prop(md, "modify_color") + + def GP_INSTANCE(self, layout, ob, md): + gpd = ob.data + + col = layout.column() + col.prop(md, "count") + col.prop(md, "use_make_objects") + + split = layout.split() + col = split.column() + col.label("Offset:") + col.prop(md, "offset", text="") + + col = split.column() + col.label("Shift:") + col.prop(md, "shift", text="") + row = col.row(align=True) + row.prop(md, "lock_axis", expand=True) + + split = layout.split() + col = split.column() + col.label("Rotation:") + col.prop(md, "rotation", text="") + col.separator() + row = col.row(align=True) + row.prop(md, "random_rot", text="", icon="TIME", toggle=True) + row.prop(md, "rot_factor", text="") + + col = split.column() + col.label("Scale:") + col.prop(md, "scale", text="") + col.separator() + row = col.row(align=True) + row.prop(md, "random_scale", text="", icon="TIME", toggle=True) + row.prop(md, "scale_factor", text="") + + split = layout.split() + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + def GP_BUILD(self, layout, ob, md): + gpd = ob.data + + split = layout.split() + + col = split.column() + col.prop(md, "mode") + if md.mode == 'CONCURRENT': + col.prop(md, "concurrent_time_alignment") + else: + col.separator() # For spacing + col.separator() + col.separator() + + col.prop(md, "transition") + sub = col.column(align=True) + sub.prop(md, "start_delay") + sub.prop(md, "length") + + col = split.column(align=True) + col.prop(md, "use_restrict_frame_range") + sub = col.column(align=True) + sub.active = md.use_restrict_frame_range + sub.prop(md, "frame_start", text="Start") + sub.prop(md, "frame_end", text="End") + col.separator() + + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + def GP_LATTICE(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label(text="Object:") + col.prop(md, "object", text="") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + layout.separator() + layout.prop(md, "strength", slider=True) + + def GP_MIRROR(self, layout, ob, md): + gpd = ob.data + + row = layout.row(align=True) + row.prop(md, "x_axis") + row.prop(md, "y_axis") + row.prop(md, "z_axis") + + # GPXX: Not implemented yet + # layout.separator() + # layout.prop(md, "clip") + + layout.label("Layer:") + row = layout.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + row = layout.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + layout.label(text="Object:") + layout.prop(md, "object", text="") + + def GP_HOOK(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.label(text="Object:") + col.prop(md, "object", text="") + if md.object and md.object.type == 'ARMATURE': + col.label(text="Bone:") + col.prop_search(md, "subtarget", md.object.data, "bones", text="") + + col = split.column() + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + + use_falloff = (md.falloff_type != 'NONE') + split = layout.split() + + layout.separator() + + row = layout.row(align=True) + if use_falloff: + row.prop(md, "falloff_radius") + row.prop(md, "strength", slider=True) + layout.prop(md, "falloff_type") + + col = layout.column() + if use_falloff: + if md.falloff_type == 'CURVE': + col.template_curve_mapping(md, "falloff_curve") + + split = layout.split() + + col = split.column() + col.prop(md, "use_falloff_uniform") + + def GP_OFFSET(self, layout, ob, md): + gpd = ob.data + split = layout.split() + + col = split.column() + col.prop(md, "location") + col.prop(md, "scale") + + col = split.column() + col.prop(md, "rotation") + + col.label("Layer:") + row = col.row(align=True) + row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL') + row.prop(md, "invert_layers", text="", icon="ARROW_LEFTRIGHT") + + col.label("Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon="ARROW_LEFTRIGHT") + + row = col.row(align=True) + row.prop(md, "pass_index", text="Pass") + row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + classes = ( DATA_PT_modifiers, + DATA_PT_gpencil_modifiers, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py new file mode 100644 index 00000000000..3798a273e09 --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py @@ -0,0 +1,135 @@ +# ##### 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> +import bpy +from bpy.types import Panel +from bpy.app.translations import pgettext_iface as iface_ + + +class ShaderFxButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "shaderfx" + bl_options = {'HIDE_HEADER'} + + +class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel): + bl_label = "Effects" + + @classmethod + def poll(cls, context): + return True + ob = context.object + return ob and ob.type == 'GPENCIL' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + 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(self, fx.type)(box, fx) + + # the mt.type enum is (ab)used for a lookup on function names + # ...to avoid lengthy if statements + # so each type must have a function here. + + def FX_BLUR(self, layout, fx): + + layout.prop(fx, "factor", text="Factor") + layout.prop(fx, "samples", text="Samples") + + layout.separator() + layout.prop(fx, "use_dof_mode") + if fx.use_dof_mode: + layout.prop(fx, "coc") + + def FX_COLORIZE(self, layout, fx): + layout.prop(fx, "mode", text="Mode") + + if fx.mode == 'BITONE': + layout.prop(fx, "low_color", text="Low Color") + if fx.mode == 'CUSTOM': + layout.prop(fx, "low_color", text="Color") + + if fx.mode == 'BITONE': + layout.prop(fx, "high_color", text="High Color") + + if fx.mode in {'BITONE', 'CUSTOM', 'TRANSPARENT'}: + layout.prop(fx, "factor") + + def FX_WAVE(self, layout, fx): + layout.prop(fx, "orientation", expand=True) + + layout.separator() + layout.prop(fx, "amplitude") + layout.prop(fx, "period") + layout.prop(fx, "phase") + + def FX_PIXEL(self, layout, fx): + layout.prop(fx, "size", text="Size") + + layout.prop(fx, "use_lines", text="Display Lines") + + col = layout.column() + col.enabled = fx.use_lines + col.prop(fx, "color") + + def FX_RIM(self, layout, fx): + layout.prop(fx, "offset", text="Offset") + + layout.prop(fx, "rim_color") + layout.prop(fx, "mask_color") + layout.prop(fx, "mode") + layout.prop(fx, "blur") + layout.prop(fx, "samples") + + def FX_SWIRL(self, layout, fx): + layout.prop(fx, "object", text="Object") + + layout.prop(fx, "radius") + layout.prop(fx, "angle") + + layout.prop(fx, "transparent") + + def FX_FLIP(self, layout, fx): + layout.prop(fx, "flip_horizontal") + layout.prop(fx, "flip_vertical") + + def FX_LIGHT(self, layout, fx): + layout.prop(fx, "object", text="Object") + + layout.prop(fx, "energy") + layout.prop(fx, "ambient") + + +classes = ( + DATA_PT_shader_fx, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_speaker.py b/release/scripts/startup/bl_ui/properties_data_speaker.py index eecb2690302..d7c93095489 100644 --- a/release/scripts/startup/bl_ui/properties_data_speaker.py +++ b/release/scripts/startup/bl_ui/properties_data_speaker.py @@ -29,14 +29,14 @@ class DataButtonsPanel: @classmethod def poll(cls, context): - engine = context.scene.render.engine + engine = context.engine return context.speaker and (engine in cls.COMPAT_ENGINES) class DATA_PT_context_speaker(DataButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -55,69 +55,73 @@ class DATA_PT_context_speaker(DataButtonsPanel, Panel): class DATA_PT_speaker(DataButtonsPanel, Panel): bl_label = "Sound" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout speaker = context.speaker - split = layout.split(percentage=0.75) + layout.template_ID(speaker, "sound", open="sound.open_mono") - split.template_ID(speaker, "sound", open="sound.open_mono") - split.prop(speaker, "muted") + layout.use_property_split = True - row = layout.row() - row.prop(speaker, "volume") - row.prop(speaker, "pitch") + layout.prop(speaker, "muted") + + col = layout.column() + col.active = not speaker.muted + col.prop(speaker, "volume", slider=True) + col.prop(speaker, "pitch") class DATA_PT_distance(DataButtonsPanel, Panel): bl_label = "Distance" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout - speaker = context.speaker + layout.use_property_split = True - split = layout.split() + speaker = context.speaker + layout.active = not speaker.muted - col = split.column() - col.label("Volume:") - col.prop(speaker, "volume_min", text="Minimum") - col.prop(speaker, "volume_max", text="Maximum") + col = layout.column() + sub = col.column(align=True) + sub.prop(speaker, "volume_min", slider=True, text="Volume Min") + sub.prop(speaker, "volume_max", slider=True, text="Max") col.prop(speaker, "attenuation") - col = split.column() - col.label("Distance:") - col.prop(speaker, "distance_max", text="Maximum") - col.prop(speaker, "distance_reference", text="Reference") + col.separator() + col.prop(speaker, "distance_max", text="Max Distance") + col.prop(speaker, "distance_reference", text="Distance Reference") class DATA_PT_cone(DataButtonsPanel, Panel): bl_label = "Cone" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + speaker = context.speaker + layout.active = not speaker.muted + + col = layout.column() - split = layout.split() + sub = col.column(align=True) + sub.prop(speaker, "cone_angle_outer", text="Angle Outer") + sub.prop(speaker, "cone_angle_inner", text="Inner") - col = split.column() - col.label("Angle:") - col.prop(speaker, "cone_angle_outer", text="Outer") - col.prop(speaker, "cone_angle_inner", text="Inner") + col.separator() - col = split.column() - col.label("Volume:") - col.prop(speaker, "cone_volume_outer", text="Outer") + col.prop(speaker, "cone_volume_outer", slider=True) class DATA_PT_custom_props_speaker(DataButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object.data" _property_type = bpy.types.Speaker diff --git a/release/scripts/startup/bl_ui/properties_data_workspace.py b/release/scripts/startup/bl_ui/properties_data_workspace.py new file mode 100644 index 00000000000..3cda3dd0abd --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_workspace.py @@ -0,0 +1,101 @@ +# ##### 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> +import bpy +from bpy.types import ( + Panel, +) + +from rna_prop_ui import PropertyPanel + + +class WorkSpaceButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "workspace" + + +class WORKSPACE_PT_owner_ids(WorkSpaceButtonsPanel, Panel): + bl_label = "Workspace Add-ons" + bl_options = {'DEFAULT_CLOSED'} + + def draw_header(self, context): + workspace = context.workspace + self.layout.prop(workspace, "use_filter_by_owner", text="") + + def draw(self, context): + layout = self.layout + # align just to pack more tightly + col = layout.box().column(align=True) + + workspace = context.workspace + userpref = context.user_preferences + + col.active = workspace.use_filter_by_owner + + import addon_utils + addon_map = {mod.__name__: mod for mod in addon_utils.modules()} + owner_ids = {owner_id.name for owner_id in workspace.owner_ids} + + for addon in userpref.addons: + module_name = addon.module + info = addon_utils.module_bl_info(addon_map[module_name]) + if not info["use_owner"]: + continue + is_enabled = module_name in owner_ids + row = col.row() + row.operator( + "wm.owner_disable" if is_enabled else "wm.owner_enable", + icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT', + text="", + emboss=False, + ).owner_id = module_name + row.label("%s: %s" % (info["category"], info["name"])) + if is_enabled: + owner_ids.remove(module_name) + + # Detect unused + if owner_ids: + layout.label(text="Unknown add-ons", icon='ERROR') + col = layout.box().column(align=True) + for module_name in sorted(owner_ids): + row = col.row() + row.operator( + "wm.owner_disable", + icon='CHECKBOX_HLT', + text="", + emboss=False, + ).owner_id = module_name + row.label(module_name) + + +class WORKSPACE_PT_custom_props(WorkSpaceButtonsPanel, PropertyPanel, Panel): + _context_path = "workspace" + _property_type = bpy.types.WorkSpace + + +classes = ( + WORKSPACE_PT_owner_ids, + WORKSPACE_PT_custom_props, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py index 7b656f9be81..12ecbeb3e6b 100644 --- a/release/scripts/startup/bl_ui/properties_freestyle.py +++ b/release/scripts/startup/bl_ui/properties_freestyle.py @@ -33,13 +33,13 @@ class RenderFreestyleButtonsPanel: def poll(cls, context): scene = context.scene with_freestyle = bpy.app.build_options.freestyle - return scene and with_freestyle and(scene.render.engine in cls.COMPAT_ENGINES) + return scene and with_freestyle and(context.engine in cls.COMPAT_ENGINES) class RENDER_PT_freestyle(RenderFreestyleButtonsPanel, Panel): bl_label = "Freestyle" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw_header(self, context): rd = context.scene.render @@ -62,34 +62,34 @@ class RENDER_PT_freestyle(RenderFreestyleButtonsPanel, Panel): # Render layer properties -class RenderLayerFreestyleButtonsPanel: +class ViewLayerFreestyleButtonsPanel: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' - bl_context = "render_layer" + bl_context = "view_layer" # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here @classmethod def poll(cls, context): scene = context.scene - rd = context.scene.render + rd = scene.render with_freestyle = bpy.app.build_options.freestyle return (scene and with_freestyle and rd.use_freestyle and - rd.layers.active and(scene.render.engine in cls.COMPAT_ENGINES)) + (context.engine in cls.COMPAT_ENGINES)) -class RenderLayerFreestyleEditorButtonsPanel(RenderLayerFreestyleButtonsPanel): +class ViewLayerFreestyleEditorButtonsPanel(ViewLayerFreestyleButtonsPanel): # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here @classmethod def poll(cls, context): if not super().poll(context): return False - rl = context.scene.render.layers.active - return rl and rl.freestyle_settings.mode == 'EDITOR' + view_layer = context.view_layer + return view_layer and view_layer.freestyle_settings.mode == 'EDITOR' -class RENDERLAYER_UL_linesets(UIList): +class VIEWLAYER_UL_linesets(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): lineset = item if self.layout_type in {'DEFAULT', 'COMPACT'}: @@ -109,18 +109,18 @@ class RENDER_MT_lineset_specials(Menu): layout.operator("scene.freestyle_lineset_paste", icon='PASTEDOWN') -class RENDERLAYER_PT_freestyle(RenderLayerFreestyleButtonsPanel, Panel): +class VIEWLAYER_PT_freestyle(ViewLayerFreestyleButtonsPanel, Panel): bl_label = "Freestyle" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout - rd = context.scene.render - rl = rd.layers.active - freestyle = rl.freestyle_settings + scene = context.scene + view_layer = context.view_layer + freestyle = view_layer.freestyle_settings - layout.active = rl.use_freestyle + layout.active = view_layer.use_freestyle row = layout.row() layout.prop(freestyle, "mode", text="Control Mode") @@ -165,9 +165,9 @@ class RENDERLAYER_PT_freestyle(RenderLayerFreestyleButtonsPanel, Panel): row.operator("scene.freestyle_module_move", icon='TRIA_DOWN', text="").direction = 'DOWN' -class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, Panel): +class VIEWLAYER_PT_freestyle_lineset(ViewLayerFreestyleEditorButtonsPanel, Panel): bl_label = "Freestyle Line Set" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw_edge_type_buttons(self, box, lineset, edge_type): # property names @@ -183,16 +183,18 @@ class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, P def draw(self, context): layout = self.layout - rd = context.scene.render - rl = rd.layers.active - freestyle = rl.freestyle_settings + scene = context.scene + rd = scene.render + + view_layer = context.view_layer + freestyle = view_layer.freestyle_settings lineset = freestyle.linesets.active - layout.active = rl.use_freestyle + layout.active = view_layer.use_freestyle row = layout.row() rows = 4 if lineset else 2 - row.template_list("RENDERLAYER_UL_linesets", "", freestyle, "linesets", freestyle.linesets, "active_index", rows=rows) + row.template_list("VIEWLAYER_UL_linesets", "", freestyle, "linesets", freestyle.linesets, "active_index", rows=rows) sub = row.column(align=True) sub.operator("scene.freestyle_lineset_add", icon='ZOOMIN', text="") @@ -256,10 +258,10 @@ class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, P row.prop(lineset, "group_negation", expand=True) -class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, Panel): +class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Panel): bl_label = "Freestyle Line Style" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw_modifier_box_header(self, box, modifier): row = box.row() @@ -376,7 +378,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, row = box.row(align=True) row.prop(modifier, "curvature_min") row.prop(modifier, "curvature_max") - freestyle = context.scene.render.layers.active.freestyle_settings + freestyle = context.view_layer.freestyle_settings if not freestyle.use_smoothness: message = "Enable Face Smoothness to use this modifier" self.draw_modifier_box_error(col.box(), modifier, message) @@ -431,7 +433,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, row = box.row(align=True) row.prop(modifier, "curvature_min") row.prop(modifier, "curvature_max") - freestyle = context.scene.render.layers.active.freestyle_settings + freestyle = context.view_layer.freestyle_settings if not freestyle.use_smoothness: message = "Enable Face Smoothness to use this modifier" self.draw_modifier_box_error(col.box(), modifier, message) @@ -503,7 +505,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, row = box.row(align=True) row.prop(modifier, "curvature_min") row.prop(modifier, "curvature_max") - freestyle = context.scene.render.layers.active.freestyle_settings + freestyle = context.view_layer.freestyle_settings if not freestyle.use_smoothness: message = "Enable Face Smoothness to use this modifier" self.draw_modifier_box_error(col.box(), modifier, message) @@ -611,11 +613,11 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, def draw(self, context): layout = self.layout - rd = context.scene.render - rl = rd.layers.active - lineset = rl.freestyle_settings.linesets.active + scene = context.scene + view_layer = context.view_layer + lineset = view_layer.freestyle_settings.linesets.active - layout.active = rl.use_freestyle + layout.active = view_layer.use_freestyle if lineset is None: return @@ -779,10 +781,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, layout.separator() row = layout.row() - if rd.use_shading_nodes: - row.prop(linestyle, "use_nodes") - else: - row.prop(linestyle, "use_texture") + row.prop(linestyle, "use_nodes") row.prop(linestyle, "texture_spacing", text="Spacing Along Stroke") row = layout.row() @@ -811,13 +810,13 @@ class MaterialFreestyleButtonsPanel: material = context.material with_freestyle = bpy.app.build_options.freestyle return with_freestyle and material and scene and scene.render.use_freestyle and \ - (scene.render.engine in cls.COMPAT_ENGINES) + (context.engine in cls.COMPAT_ENGINES) class MATERIAL_PT_freestyle_line(MaterialFreestyleButtonsPanel, Panel): bl_label = "Freestyle Line" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout @@ -831,11 +830,11 @@ class MATERIAL_PT_freestyle_line(MaterialFreestyleButtonsPanel, Panel): classes = ( RENDER_PT_freestyle, - RENDERLAYER_UL_linesets, + VIEWLAYER_UL_linesets, RENDER_MT_lineset_specials, - RENDERLAYER_PT_freestyle, - RENDERLAYER_PT_freestyle_lineset, - RENDERLAYER_PT_freestyle_linestyle, + VIEWLAYER_PT_freestyle, + VIEWLAYER_PT_freestyle_lineset, + VIEWLAYER_PT_freestyle_linestyle, MATERIAL_PT_freestyle_line, ) diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py deleted file mode 100644 index ac51b97e87d..00000000000 --- a/release/scripts/startup/bl_ui/properties_game.py +++ /dev/null @@ -1,881 +0,0 @@ -# ##### 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> -import bpy -from bpy.types import Panel, Menu - - -class PhysicsButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "physics" - - -class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel): - bl_label = "Physics" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - ob = context.active_object - rd = context.scene.render - return ob and ob.game and (rd.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - ob = context.active_object - game = ob.game - soft = ob.game.soft_body - - layout.prop(game, "physics_type") - layout.separator() - - physics_type = game.physics_type - - if physics_type == 'CHARACTER': - layout.prop(game, "use_actor") - layout.prop(ob, "hide_render", text="Invisible") # out of place but useful - layout.prop(game, "step_height", slider=True) - layout.prop(game, "jump_speed") - layout.prop(game, "fall_speed") - layout.prop(game, "jump_max") - - elif physics_type in {'DYNAMIC', 'RIGID_BODY'}: - split = layout.split() - - col = split.column() - col.prop(game, "use_actor") - col.prop(game, "use_ghost") - col.prop(ob, "hide_render", text="Invisible") # out of place but useful - - col = split.column() - col.prop(game, "use_material_physics_fh") - col.prop(game, "use_rotate_from_normal") - col.prop(game, "use_sleep") - - layout.separator() - - split = layout.split() - - col = split.column() - col.label(text="Attributes:") - col.prop(game, "mass") - col.prop(game, "radius") - col.prop(game, "form_factor") - - col = split.column() - sub = col.column() - sub.prop(game, "use_anisotropic_friction") - subsub = sub.column() - subsub.active = game.use_anisotropic_friction - subsub.prop(game, "friction_coefficients", text="", slider=True) - - split = layout.split() - - col = split.column() - col.label(text="Linear Velocity:") - sub = col.column(align=True) - sub.prop(game, "velocity_min", text="Minimum") - sub.prop(game, "velocity_max", text="Maximum") - col.label(text="Angular Velocity:") - sub = col.column(align=True) - sub.prop(game, "angular_velocity_min", text="Minimum") - sub.prop(game, "angular_velocity_max", text="Maximum") - - col = split.column() - col.label(text="Damping:") - sub = col.column(align=True) - sub.prop(game, "damping", text="Translation", slider=True) - sub.prop(game, "rotation_damping", text="Rotation", slider=True) - - layout.separator() - - split = layout.split() - - col = split.column() - col.label(text="Lock Translation:") - col.prop(game, "lock_location_x", text="X") - col.prop(game, "lock_location_y", text="Y") - col.prop(game, "lock_location_z", text="Z") - - if physics_type == 'RIGID_BODY': - col = split.column() - col.label(text="Lock Rotation:") - col.prop(game, "lock_rotation_x", text="X") - col.prop(game, "lock_rotation_y", text="Y") - col.prop(game, "lock_rotation_z", text="Z") - - elif physics_type == 'SOFT_BODY': - col = layout.column() - col.prop(game, "use_actor") - col.prop(game, "use_ghost") - col.prop(ob, "hide_render", text="Invisible") - - layout.separator() - - split = layout.split() - - col = split.column() - col.label(text="Attributes:") - col.prop(game, "mass") - # disabled in the code - # col.prop(soft, "weld_threshold") - col.prop(soft, "location_iterations") - col.prop(soft, "linear_stiffness", slider=True) - col.prop(soft, "dynamic_friction", slider=True) - col.prop(soft, "collision_margin", slider=True) - col.prop(soft, "use_bending_constraints", text="Bending Constraints") - - col = split.column() - col.prop(soft, "use_shape_match") - sub = col.column() - sub.active = soft.use_shape_match - sub.prop(soft, "shape_threshold", slider=True) - - col.separator() - - col.label(text="Cluster Collision:") - col.prop(soft, "use_cluster_rigid_to_softbody") - col.prop(soft, "use_cluster_soft_to_softbody") - sub = col.column() - sub.active = (soft.use_cluster_rigid_to_softbody or soft.use_cluster_soft_to_softbody) - sub.prop(soft, "cluster_iterations", text="Iterations") - - elif physics_type == 'STATIC': - col = layout.column() - col.prop(game, "use_actor") - col.prop(game, "use_ghost") - col.prop(game, "use_record_animation") - col.prop(ob, "hide_render", text="Invisible") - - layout.separator() - - split = layout.split() - - col = split.column() - col.label(text="Attributes:") - col.prop(game, "radius") - - col = split.column() - sub = col.column() - sub.prop(game, "use_anisotropic_friction") - subsub = sub.column() - subsub.active = game.use_anisotropic_friction - subsub.prop(game, "friction_coefficients", text="", slider=True) - - elif physics_type == 'SENSOR': - col = layout.column() - col.prop(game, "use_actor", text="Detect Actors") - col.prop(ob, "hide_render", text="Invisible") - - elif physics_type in {'INVISIBLE', 'NO_COLLISION', 'OCCLUDER'}: - layout.prop(ob, "hide_render", text="Invisible") - - elif physics_type == 'NAVMESH': - layout.operator("mesh.navmesh_face_copy") - layout.operator("mesh.navmesh_face_add") - - layout.separator() - - layout.operator("mesh.navmesh_reset") - layout.operator("mesh.navmesh_clear") - - -class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel): - bl_label = "Collision Bounds" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - game = context.object.game - rd = context.scene.render - return (rd.engine in cls.COMPAT_ENGINES) \ - and (game.physics_type in {'SENSOR', 'STATIC', 'DYNAMIC', 'RIGID_BODY', 'CHARACTER', 'SOFT_BODY'}) - - def draw_header(self, context): - game = context.active_object.game - - self.layout.prop(game, "use_collision_bounds", text="") - - def draw(self, context): - layout = self.layout - - game = context.active_object.game - split = layout.split() - split.active = game.use_collision_bounds - - col = split.column() - col.prop(game, "collision_bounds_type", text="Bounds") - - row = col.row() - row.prop(game, "collision_margin", text="Margin", slider=True) - - sub = row.row() - sub.active = game.physics_type not in {'SOFT_BODY', 'CHARACTER'} - sub.prop(game, "use_collision_compound", text="Compound") - - layout.separator() - split = layout.split() - col = split.column() - col.prop(game, "collision_group") - col = split.column() - col.prop(game, "collision_mask") - - -class PHYSICS_PT_game_obstacles(PhysicsButtonsPanel, Panel): - bl_label = "Create Obstacle" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - game = context.object.game - rd = context.scene.render - return (rd.engine in cls.COMPAT_ENGINES) \ - and (game.physics_type in {'SENSOR', 'STATIC', 'DYNAMIC', 'RIGID_BODY', 'SOFT_BODY', 'CHARACTER', 'NO_COLLISION'}) - - def draw_header(self, context): - game = context.active_object.game - - self.layout.prop(game, "use_obstacle_create", text="") - - def draw(self, context): - layout = self.layout - - game = context.active_object.game - - layout.active = game.use_obstacle_create - - row = layout.row() - row.prop(game, "obstacle_radius", text="Radius") - row.label() - - -class RenderButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "render" - - @classmethod - def poll(cls, context): - rd = context.scene.render - return (rd.engine in cls.COMPAT_ENGINES) - - -class RENDER_PT_embedded(RenderButtonsPanel, Panel): - bl_label = "Embedded Player" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - rd = context.scene.render - - row = layout.row() - row.operator("view3d.game_start", text="Start") - row = layout.row() - row.label(text="Resolution:") - row = layout.row(align=True) - row.prop(rd, "resolution_x", slider=False, text="X") - row.prop(rd, "resolution_y", slider=False, text="Y") - - -class RENDER_PT_game_player(RenderButtonsPanel, Panel): - bl_label = "Standalone Player" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - import sys - layout = self.layout - not_osx = sys.platform != "darwin" - - gs = context.scene.game_settings - - row = layout.row() - row.operator("wm.blenderplayer_start", text="Start") - row = layout.row() - row.label(text="Resolution:") - row = layout.row(align=True) - row.active = not_osx or not gs.show_fullscreen - row.prop(gs, "resolution_x", slider=False, text="X") - row.prop(gs, "resolution_y", slider=False, text="Y") - row = layout.row() - col = row.column() - col.prop(gs, "show_fullscreen") - - if not_osx: - col = row.column() - col.prop(gs, "use_desktop") - col.active = gs.show_fullscreen - - col = layout.column() - col.label(text="Quality:") - col.prop(gs, "samples") - col = layout.column(align=True) - col.prop(gs, "depth", text="Bit Depth", slider=False) - col.prop(gs, "frequency", text="Refresh Rate", slider=False) - - -class RENDER_PT_game_stereo(RenderButtonsPanel, Panel): - bl_label = "Stereo" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - gs = context.scene.game_settings - stereo_mode = gs.stereo - - # stereo options: - layout.row().prop(gs, "stereo", expand=True) - - # stereo: - if stereo_mode == 'STEREO': - layout.prop(gs, "stereo_mode") - layout.prop(gs, "stereo_eye_separation") - - # dome: - elif stereo_mode == 'DOME': - layout.prop(gs, "dome_mode", text="Dome Type") - - dome_type = gs.dome_mode - - split = layout.split() - - if dome_type in {'FISHEYE', 'TRUNCATED_REAR', 'TRUNCATED_FRONT'}: - col = split.column() - col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True) - col.prop(gs, "dome_angle", slider=True) - - col = split.column() - col.prop(gs, "dome_tessellation", text="Tessellation") - col.prop(gs, "dome_tilt") - - elif dome_type == 'PANORAM_SPH': - col = split.column() - col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True) - - col = split.column() - col.prop(gs, "dome_tessellation", text="Tessellation") - - else: # cube map - col = split.column() - col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True) - - col = split.column() - - layout.prop(gs, "dome_text") - - -class RENDER_PT_game_shading(RenderButtonsPanel, Panel): - bl_label = "Shading" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - gs = context.scene.game_settings - - layout.row().prop(gs, "material_mode", expand=True) - - if gs.material_mode == 'GLSL': - split = layout.split() - - col = split.column() - col.prop(gs, "use_glsl_lights", text="Lights") - col.prop(gs, "use_glsl_shaders", text="Shaders") - col.prop(gs, "use_glsl_shadows", text="Shadows") - col.prop(gs, "use_glsl_environment_lighting", text="Environment Lighting") - - col = split.column() - col.prop(gs, "use_glsl_ramps", text="Ramps") - col.prop(gs, "use_glsl_nodes", text="Nodes") - col.prop(gs, "use_glsl_extra_textures", text="Extra Textures") - - -class RENDER_PT_game_system(RenderButtonsPanel, Panel): - bl_label = "System" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - gs = context.scene.game_settings - col = layout.column() - row = col.row() - col = row.column() - col.prop(gs, "use_frame_rate") - col.prop(gs, "use_restrict_animation_updates") - col.prop(gs, "use_material_caching") - col = row.column() - col.prop(gs, "use_display_lists") - col.active = gs.raster_storage != 'VERTEX_BUFFER_OBJECT' - - row = layout.row() - row.prop(gs, "vsync") - - row = layout.row() - row.prop(gs, "raster_storage") - - row = layout.row() - row.label("Exit Key") - row.prop(gs, "exit_key", text="", event=True) - - -class RENDER_PT_game_display(RenderButtonsPanel, Panel): - bl_label = "Display" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - gs = context.scene.game_settings - - layout.prop(context.scene.render, "fps", text="Animation Frame Rate", slider=False) - - flow = layout.column_flow() - flow.prop(gs, "show_debug_properties", text="Debug Properties") - flow.prop(gs, "show_framerate_profile", text="Framerate and Profile") - flow.prop(gs, "show_physics_visualization", text="Physics Visualization") - flow.prop(gs, "use_deprecation_warnings") - flow.prop(gs, "show_mouse", text="Mouse Cursor") - - col = layout.column() - col.label(text="Framing:") - col.row().prop(gs, "frame_type", expand=True) - if gs.frame_type == 'LETTERBOX': - col.prop(gs, "frame_color", text="") - - -class SceneButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "scene" - - -class SCENE_PT_game_physics(SceneButtonsPanel, Panel): - bl_label = "Physics" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - scene = context.scene - return (scene.render.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - gs = context.scene.game_settings - - layout.prop(gs, "physics_engine", text="Engine") - if gs.physics_engine != 'NONE': - layout.prop(gs, "physics_gravity", text="Gravity") - - split = layout.split() - - col = split.column() - col.label(text="Physics Steps:") - sub = col.column(align=True) - sub.prop(gs, "physics_step_max", text="Max") - sub.prop(gs, "physics_step_sub", text="Substeps") - col.prop(gs, "fps", text="FPS") - - col = split.column() - col.label(text="Logic Steps:") - col.prop(gs, "logic_step_max", text="Max") - - col = layout.column() - col.label(text="Physics Deactivation:") - sub = col.row(align=True) - sub.prop(gs, "deactivation_linear_threshold", text="Linear Threshold") - sub.prop(gs, "deactivation_angular_threshold", text="Angular Threshold") - sub = col.row() - sub.prop(gs, "deactivation_time", text="Time") - - col = layout.column() - col.prop(gs, "use_occlusion_culling", text="Occlusion Culling") - sub = col.column() - sub.active = gs.use_occlusion_culling - sub.prop(gs, "occlusion_culling_resolution", text="Resolution") - - else: - split = layout.split() - - col = split.column() - col.label(text="Physics Steps:") - col.prop(gs, "fps", text="FPS") - - col = split.column() - col.label(text="Logic Steps:") - col.prop(gs, "logic_step_max", text="Max") - - -class SCENE_PT_game_physics_obstacles(SceneButtonsPanel, Panel): - bl_label = "Obstacle Simulation" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - scene = context.scene - return (scene.render.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - gs = context.scene.game_settings - - layout.prop(gs, "obstacle_simulation", text="Type") - if gs.obstacle_simulation != 'NONE': - layout.prop(gs, "level_height") - layout.prop(gs, "show_obstacle_simulation") - - -class SCENE_PT_game_navmesh(SceneButtonsPanel, Panel): - bl_label = "Navigation Mesh" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - scene = context.scene - return (scene and scene.render.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - rd = context.scene.game_settings.recast_data - - layout.operator("mesh.navmesh_make", text="Build Navigation Mesh") - - col = layout.column() - col.label(text="Rasterization:") - row = col.row() - row.prop(rd, "cell_size") - row.prop(rd, "cell_height") - - col = layout.column() - col.label(text="Agent:") - split = col.split() - - col = split.column() - col.prop(rd, "agent_height", text="Height") - col.prop(rd, "agent_radius", text="Radius") - - col = split.column() - col.prop(rd, "slope_max") - col.prop(rd, "climb_max") - - col = layout.column() - col.label(text="Region:") - row = col.row() - row.prop(rd, "region_min_size") - if rd.partitioning != 'LAYERS': - row.prop(rd, "region_merge_size") - - col = layout.column() - col.prop(rd, "partitioning") - - col = layout.column() - col.label(text="Polygonization:") - split = col.split() - - col = split.column() - col.prop(rd, "edge_max_len") - col.prop(rd, "edge_max_error") - - split.prop(rd, "verts_per_poly") - - col = layout.column() - col.label(text="Detail Mesh:") - row = col.row() - row.prop(rd, "sample_dist") - row.prop(rd, "sample_max_error") - - -class SCENE_PT_game_hysteresis(SceneButtonsPanel, Panel): - bl_label = "Level of Detail" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - scene = context.scene - return (scene and scene.render.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - gs = context.scene.game_settings - - row = layout.row() - row.prop(gs, "use_scene_hysteresis", text="Hysteresis") - row = layout.row() - row.active = gs.use_scene_hysteresis - row.prop(gs, "scene_hysteresis_percentage", text="") - - -class WorldButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "world" - - -class WORLD_PT_game_context_world(WorldButtonsPanel, Panel): - bl_label = "" - bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - rd = context.scene.render - return (context.scene) and (rd.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - scene = context.scene - world = context.world - space = context.space_data - - split = layout.split(percentage=0.65) - if scene: - split.template_ID(scene, "world", new="world.new") - elif world: - split.template_ID(space, "pin_id") - - -class WORLD_PT_game_world(WorldButtonsPanel, Panel): - bl_label = "World" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - scene = context.scene - return (scene.world and scene.render.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - world = context.world - - row = layout.row() - row.column().prop(world, "horizon_color") - row.column().prop(world, "zenith_color") - row.column().prop(world, "ambient_color") - - -class WORLD_PT_game_environment_lighting(WorldButtonsPanel, Panel): - bl_label = "Environment Lighting" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - scene = context.scene - return (scene.world and scene.render.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - light = context.world.light_settings - self.layout.prop(light, "use_environment_light", text="") - - def draw(self, context): - layout = self.layout - - light = context.world.light_settings - - layout.active = light.use_environment_light - - split = layout.split() - split.prop(light, "environment_energy", text="Energy") - split.prop(light, "environment_color", text="") - - -class WORLD_PT_game_mist(WorldButtonsPanel, Panel): - bl_label = "Mist" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - scene = context.scene - return (scene.world and scene.render.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - world = context.world - - self.layout.prop(world.mist_settings, "use_mist", text="") - - def draw(self, context): - layout = self.layout - - world = context.world - - layout.active = world.mist_settings.use_mist - - layout.prop(world.mist_settings, "falloff") - - row = layout.row(align=True) - row.prop(world.mist_settings, "start") - row.prop(world.mist_settings, "depth") - - layout.prop(world.mist_settings, "intensity", text="Minimum Intensity") - - -class DataButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "data" - - -class DATA_PT_shadow_game(DataButtonsPanel, Panel): - bl_label = "Shadow" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - COMPAT_LIGHTS = {'SPOT', 'SUN'} - lamp = context.lamp - engine = context.scene.render.engine - return (lamp and lamp.type in COMPAT_LIGHTS) and (engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - lamp = context.lamp - - self.layout.prop(lamp, "use_shadow", text="") - - def draw(self, context): - layout = self.layout - - lamp = context.lamp - - layout.active = lamp.use_shadow - - split = layout.split() - - col = split.column() - col.prop(lamp, "shadow_color", text="") - if lamp.type == 'SUN': - col.prop(lamp, "show_shadow_box") - - col = split.column() - col.prop(lamp, "use_shadow_layer", text="This Layer Only") - col.prop(lamp, "use_only_shadow") - - col = layout.column() - col.label("Buffer Type:") - col.prop(lamp, "ge_shadow_buffer_type", text="", toggle=True) - col.label("Quality:") - col = layout.column(align=True) - col.prop(lamp, "shadow_buffer_size", text="Size") - col.prop(lamp, "shadow_buffer_bias", text="Bias") - col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias") - - row = layout.row() - row.label("Clipping:") - row = layout.row(align=True) - row.prop(lamp, "shadow_buffer_clip_start", text="Clip Start") - row.prop(lamp, "shadow_buffer_clip_end", text="Clip End") - - if lamp.type == 'SUN': - row = layout.row() - row.prop(lamp, "shadow_frustum_size", text="Frustum Size") - - -class ObjectButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "object" - - -class OBJECT_MT_lod_tools(Menu): - bl_label = "Level Of Detail Tools" - - def draw(self, context): - layout = self.layout - - layout.operator("object.lod_by_name", text="Set By Name") - layout.operator("object.lod_generate", text="Generate") - layout.operator("object.lod_clear_all", text="Clear All", icon='PANEL_CLOSE') - - -class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel): - bl_label = "Levels of Detail" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - return context.scene.render.engine in cls.COMPAT_ENGINES - - def draw(self, context): - layout = self.layout - ob = context.object - gs = context.scene.game_settings - - col = layout.column() - - for i, level in enumerate(ob.lod_levels): - if i == 0: - continue - box = col.box() - row = box.row() - row.prop(level, "object", text="") - row.operator("object.lod_remove", text="", icon='PANEL_CLOSE').index = i - - row = box.row() - row.prop(level, "distance") - row = row.row(align=True) - row.prop(level, "use_mesh", text="") - row.prop(level, "use_material", text="") - - row = box.row() - row.active = gs.use_scene_hysteresis - row.prop(level, "use_object_hysteresis", text="Hysteresis Override") - row = box.row() - row.active = gs.use_scene_hysteresis and level.use_object_hysteresis - row.prop(level, "object_hysteresis_percentage", text="") - - row = col.row(align=True) - row.operator("object.lod_add", text="Add", icon='ZOOMIN') - row.menu("OBJECT_MT_lod_tools", text="", icon='TRIA_DOWN') - - -classes = ( - PHYSICS_PT_game_physics, - PHYSICS_PT_game_collision_bounds, - PHYSICS_PT_game_obstacles, - RENDER_PT_embedded, - RENDER_PT_game_player, - RENDER_PT_game_stereo, - RENDER_PT_game_shading, - RENDER_PT_game_system, - RENDER_PT_game_display, - SCENE_PT_game_physics, - SCENE_PT_game_physics_obstacles, - SCENE_PT_game_navmesh, - SCENE_PT_game_hysteresis, - WORLD_PT_game_context_world, - WORLD_PT_game_world, - WORLD_PT_game_environment_lighting, - WORLD_PT_game_mist, - DATA_PT_shadow_game, - OBJECT_MT_lod_tools, - OBJECT_PT_levels_of_detail, -) - -if __name__ == "__main__": # only for live edit. - from bpy.utils import register_class - for cls in classes: - register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 72d8a53dd69..336e4acfd8f 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -18,45 +18,30 @@ # <pep8 compliant> - +import bpy from bpy.types import Menu, UIList from bpy.app.translations import pgettext_iface as iface_ def gpencil_stroke_placement_settings(context, layout): if context.space_data.type == 'VIEW_3D': - propname = "gpencil_stroke_placement_view3d" + propname = "annotation_stroke_placement_view3d" elif context.space_data.type == 'SEQUENCE_EDITOR': - propname = "gpencil_stroke_placement_sequencer_preview" + propname = "annotation_stroke_placement_sequencer_preview" elif context.space_data.type == 'IMAGE_EDITOR': - propname = "gpencil_stroke_placement_image_editor" + propname = "annotation_stroke_placement_image_editor" else: - propname = "gpencil_stroke_placement_view2d" + propname = "annotation_stroke_placement_view2d" ts = context.tool_settings col = layout.column(align=True) - col.label(text="Stroke Placement:") - - row = col.row(align=True) - row.prop_enum(ts, propname, 'VIEW') - row.prop_enum(ts, propname, 'CURSOR') - - if context.space_data.type == 'VIEW_3D': + if context.space_data.type != 'VIEW_3D': + col.label(text="Stroke Placement:") row = col.row(align=True) - row.prop_enum(ts, propname, 'SURFACE') - row.prop_enum(ts, propname, 'STROKE') - - row = col.row(align=False) - row.active = getattr(ts, propname) in {'SURFACE', 'STROKE'} - row.prop(ts, "use_gpencil_stroke_endpoints") - - if context.scene.tool_settings.gpencil_stroke_placement_view3d == 'CURSOR': - row = col.row(align=True) - row.label("Lock axis:") - row = col.row(align=True) - row.prop(ts.gpencil_sculpt, "lockaxis", expand=True) + row.prop_enum(ts, propname, 'VIEW') + row.prop_enum(ts, propname, 'CURSOR', text="Cursor") def gpencil_active_brush_settings_simple(context, layout): @@ -73,7 +58,7 @@ def gpencil_active_brush_settings_simple(context, layout): row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA') row.prop(brush, "name", text="") - col.prop(brush, "line_width", slider=True) + col.prop(brush, "size", slider=True) row = col.row(align=True) row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE') row.prop(brush, "pen_sensitivity_factor", slider=True) @@ -90,6 +75,7 @@ def gpencil_active_brush_settings_simple(context, layout): row.prop(brush, "angle_factor", text="Factor", slider=True) +# XXX: To be replaced with active tools class GreasePencilDrawingToolsPanel: # subclass must set # bl_space_type = 'IMAGE_EDITOR' @@ -97,6 +83,10 @@ class GreasePencilDrawingToolsPanel: bl_category = "Grease Pencil" bl_region_type = 'TOOLS' + @classmethod + def poll(cls, context): + return True + @staticmethod def draw(self, context): layout = self.layout @@ -108,12 +98,12 @@ class GreasePencilDrawingToolsPanel: col.label(text="Draw:") row = col.row(align=True) - row.operator("gpencil.draw", icon='GREASEPENCIL', text="Draw").mode = 'DRAW' - row.operator("gpencil.draw", icon='FORCE_CURVE', text="Erase").mode = 'ERASER' # XXX: Needs a dedicated icon + row.operator("gpencil.annotate", icon='GREASEPENCIL', text="Draw").mode = 'DRAW' + row.operator("gpencil.annotate", icon='FORCE_CURVE', text="Erase").mode = 'ERASER' # XXX: Needs a dedicated icon row = col.row(align=True) - row.operator("gpencil.draw", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT' - row.operator("gpencil.draw", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY' + row.operator("gpencil.annotate", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT' + row.operator("gpencil.annotate", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY' col.separator() @@ -121,15 +111,15 @@ class GreasePencilDrawingToolsPanel: sub.operator("gpencil.blank_frame_add", icon='NEW') sub.operator("gpencil.active_frames_delete_all", icon='X', text="Delete Frame(s)") - sub = col.column(align=True) - sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing") - sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing") - sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back") + #sub = col.column(align=True) + #sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing") + #sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing") + #sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back") col.separator() col.separator() - if context.space_data.type in {'VIEW_3D', 'CLIP_EDITOR'}: + if context.space_data.type in {'CLIP_EDITOR'}: col.separator() col.label("Data Source:") row = col.row(align=True) @@ -138,8 +128,8 @@ class GreasePencilDrawingToolsPanel: elif is_clip_editor: row.prop(context.space_data, "grease_pencil_source", expand=True) - col.separator() - col.separator() + # col.separator() + # col.separator() gpencil_stroke_placement_settings(context, col) @@ -152,22 +142,13 @@ class GreasePencilDrawingToolsPanel: col = layout.column(align=True) col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True) - if is_3d_view: - col.separator() - col.separator() - - col.label(text="Tools:") - col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type") - col.operator("view3d.ruler") - class GreasePencilStrokeEditPanel: # subclass must set # bl_space_type = 'IMAGE_EDITOR' bl_label = "Edit Strokes" - bl_category = "Grease Pencil" + bl_category = "Tools" bl_region_type = 'TOOLS' - bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): @@ -196,7 +177,7 @@ class GreasePencilStrokeEditPanel: col.operator("gpencil.select_linked") col.operator("gpencil.select_more") col.operator("gpencil.select_less") - col.operator("gpencil.palettecolor_select") + col.operator("gpencil.select_alternate") layout.label(text="Edit:") row = layout.row(align=True) @@ -220,247 +201,125 @@ class GreasePencilStrokeEditPanel: layout.separator() - col = layout.column(align=True) - col.operator("transform.bend", text="Bend") - col.operator("transform.mirror", text="Mirror") - col.operator("transform.shear", text="Shear") - col.operator("transform.tosphere", text="To Sphere") - layout.separator() col = layout.column(align=True) col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction") - col.operator("gpencil.stroke_change_color", text="Move to Color") - - if is_3d_view: - layout.separator() + col.operator("gpencil.stroke_change_color", text="Assign Material") layout.separator() col = layout.column(align=True) col.operator("gpencil.stroke_subdivide", text="Subdivide") - col.operator("gpencil.stroke_join", text="Join").type = 'JOIN' - col.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY' - col.operator("gpencil.stroke_flip", text="Flip Direction") - - gpd = context.gpencil_data - if gpd: - col.prop(gpd, "show_stroke_direction", text="Show Directions") - - if is_3d_view: - layout.separator() - layout.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type") - - -class GreasePencilInterpolatePanel: - bl_space_type = 'VIEW_3D' - bl_label = "Interpolate" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): - if context.gpencil_data is None: - return False - elif context.space_data.type != 'VIEW_3D': - return False - - gpd = context.gpencil_data - return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode) - - @staticmethod - def draw(self, context): - layout = self.layout - settings = context.tool_settings.gpencil_interpolate - - col = layout.column(align=True) - col.operator("gpencil.interpolate", text="Interpolate") - col.operator("gpencil.interpolate_sequence", text="Sequence") - col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns") - - col = layout.column(align=True) - col.label(text="Options:") - col.prop(settings, "interpolate_all_layers") - col.prop(settings, "interpolate_selected_only") - - col = layout.column(align=True) - col.label(text="Sequence Options:") - col.prop(settings, "type") - if settings.type == 'CUSTOM': - box = layout.box() - # TODO: Options for loading/saving curve presets? - box.template_curve_mapping(settings, "interpolation_curve", brush=True) - elif settings.type != 'LINEAR': - col.prop(settings, "easing") - - if settings.type == 'BACK': - layout.prop(settings, "back") - elif setting.type == 'ELASTIC': - sub = layout.column(align=True) - sub.prop(settings, "amplitude") - sub.prop(settings, "period") - - -class GreasePencilBrushPanel: - # subclass must set - # bl_space_type = 'IMAGE_EDITOR' - bl_label = "Drawing Brushes" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' + row = col.row(align=True) + row.operator("gpencil.stroke_simplify_fixed", text="Simplify") + row.operator("gpencil.stroke_simplify", text="Adaptative") - @staticmethod - def draw(self, context): - layout = self.layout + col.separator() - row = layout.row() - col = row.column() - ts = context.scene.tool_settings - if len(ts.gpencil_brushes) >= 2: - brows = 3 - else: - brows = 2 - col.template_list("GPENCIL_UL_brush", "", ts, "gpencil_brushes", ts.gpencil_brushes, "active_index", rows=brows) + row = col.row(align=True) + row.operator("gpencil.stroke_join", text="Join").type = 'JOIN' + row.operator("gpencil.stroke_join", text="& Copy").type = 'JOINCOPY' - col = row.column() + col.operator("gpencil.stroke_flip", text="Flip Direction") - sub = col.column(align=True) - sub.operator("gpencil.brush_add", icon='ZOOMIN', text="") - sub.operator("gpencil.brush_remove", icon='ZOOMOUT', text="") - sub.menu("GPENCIL_MT_brush_specials", icon='DOWNARROW_HLT', text="") - brush = context.active_gpencil_brush - if brush: - if len(ts.gpencil_brushes) > 1: - col.separator() - sub = col.column(align=True) - sub.operator("gpencil.brush_move", icon='TRIA_UP', text="").type = 'UP' - sub.operator("gpencil.brush_move", icon='TRIA_DOWN', text="").type = 'DOWN' + if is_3d_view: + layout.separator() - # Brush details - if brush is not None: - row = layout.row() - row.prop(brush, "line_width") - row = layout.row(align=True) - row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE') - row.prop(brush, "pen_sensitivity_factor", slider=True) - row.prop(brush, "use_pressure", text="", icon='STYLUS_PRESSURE') - row = layout.row(align=True) - row.prop(brush, "use_random_strength", text="", icon='RNDCURVE') - row.prop(brush, "strength", slider=True) - row.prop(brush, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') - row = layout.row(align=True) - row.prop(brush, "random_press", slider=True) + col = layout.column(align=True) + col.operator_menu_enum("gpencil.stroke_separate", text="Separate...", property="mode") + col.operator("gpencil.stroke_split", text="Split") - row = layout.row(align=True) - row.prop(brush, "jitter", slider=True) - row.prop(brush, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE') - row = layout.row() - row.prop(brush, "angle", slider=True) - row.prop(brush, "angle_factor", text="Factor", slider=True) - - box = layout.box() - col = box.column(align=True) - col.label(text="Stroke Quality:") - col.prop(brush, "pen_smooth_factor") - col.prop(brush, "pen_smooth_steps") - col.separator() - row = col.row(align=False) - row.prop(brush, "pen_subdivision_steps") - row.prop(brush, "random_subdiv", text="Randomness", slider=True) + col = layout.column(align=True) + col.label(text="Cleanup:") + col.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type") + col.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode") class GreasePencilStrokeSculptPanel: # subclass must set # bl_space_type = 'IMAGE_EDITOR' bl_label = "Sculpt Strokes" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' - - @classmethod - def poll(cls, context): - if context.gpencil_data is None: - return False - - gpd = context.gpencil_data - return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode) + bl_category = "Tools" @staticmethod def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False settings = context.tool_settings.gpencil_sculpt tool = settings.tool brush = settings.brush - layout.column().prop(settings, "tool") + layout.template_icon_view(settings, "tool", show_labels=True) - col = layout.column() - col.prop(brush, "size", slider=True) - row = col.row(align=True) + layout.prop(brush, "size", slider=True) + row = layout.row(align=True) row.prop(brush, "strength", slider=True) row.prop(brush, "use_pressure_strength", text="") - col.prop(brush, "use_falloff") - if tool in {'SMOOTH', 'RANDOMIZE'}: - row = layout.row(align=True) - row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True) - row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True) - row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True) - layout.separator() + layout.prop(brush, "use_falloff") - if tool == 'THICKNESS': - layout.row().prop(brush, "direction", expand=True) - elif tool == 'PINCH': - row = layout.row(align=True) - row.prop_enum(brush, "direction", 'ADD', text="Pinch") - row.prop_enum(brush, "direction", 'SUBTRACT', text="Inflate") - elif settings.tool == 'TWIST': - row = layout.row(align=True) - row.prop_enum(brush, "direction", 'SUBTRACT', text="CW") - row.prop_enum(brush, "direction", 'ADD', text="CCW") + if tool in {'SMOOTH', 'RANDOMIZE'}: + layout.prop(settings, "affect_position", text="Affect Position") + layout.prop(settings, "affect_strength", text="Affect Strength") + layout.prop(settings, "affect_thickness", text="Affect Thickness") - row = layout.row(align=True) - row.prop(settings, "use_select_mask") - row = layout.row(align=True) - row.prop(settings, "selection_alpha", slider=True) + if tool == 'SMOOTH': + layout.prop(brush, "affect_pressure") - if tool == 'SMOOTH': - layout.prop(brush, "affect_pressure") + layout.prop(settings, "affect_uv", text="Affect UV") + if tool in {'THICKNESS', 'PINCH', 'TWIST'}: + layout.prop(brush, "direction", expand=True) -class GreasePencilBrushCurvesPanel: - # subclass must set - # bl_space_type = 'IMAGE_EDITOR' - bl_label = "Brush Curves" - bl_category = "Grease Pencil" - bl_region_type = 'TOOLS' + +# GP Object Tool Settings +class GreasePencilAppearancePanel: + bl_label = "Brush Appearance" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): - if context.active_gpencil_brush is None: - return False - - brush = context.active_gpencil_brush - return bool(brush) + ob = context.active_object + return ob and ob.type == 'GPENCIL' @staticmethod def draw(self, context): layout = self.layout - brush = context.active_gpencil_brush - # Brush - layout.label("Sensitivity") - box = layout.box() - box.template_curve_mapping(brush, "curve_sensitivity", brush=True) + layout.use_property_split = True + layout.use_property_decorate = False - layout.label("Strength") - box = layout.box() - box.template_curve_mapping(brush, "curve_strength", brush=True) + ob = context.active_object - layout.label("Jitter") - box = layout.box() - box.template_curve_mapping(brush, "curve_jitter", brush=True) + if ob.mode == 'GPENCIL_PAINT': + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + layout.prop(gp_settings, "gpencil_brush_type", text="Brush Type") + + sub = layout.column(align=True) + sub.enabled = not brush.use_custom_icon + sub.prop(gp_settings, "gp_icon", text="Icon") + + layout.prop(brush, "use_custom_icon") + sub = layout.column() + sub.active = brush.use_custom_icon + sub.prop(brush, "icon_filepath", text="") + + layout.prop(gp_settings, "use_cursor", text="Show Brush") + + if gp_settings.gpencil_brush_type == 'FILL': + layout.prop(brush, "cursor_color_add", text="Color") + + elif ob.mode in ('GPENCIL_SCULPT', 'GPENCIL_WEIGHT'): + settings = context.tool_settings.gpencil_sculpt + brush = settings.brush + + col = layout.column(align=True) + col.prop(brush, "use_cursor", text="Show Brush") + col.row().prop(brush, "cursor_color_add", text="Add") + col.row().prop(brush, "cursor_color_sub", text="Subtract") -############################### class GPENCIL_MT_pie_tool_palette(Menu): """A pie menu for quick access to Grease Pencil tools""" @@ -517,6 +376,7 @@ class GPENCIL_MT_pie_tool_palette(Menu): col.operator("gpencil.select_border", text="Border Select", icon='BORDER_RECT') col.operator("gpencil.select_circle", text="Circle Select", icon='META_EMPTY') col.operator("gpencil.select_lasso", text="Lasso Select", icon='BORDER_LASSO') + col.operator("gpencil.select_alternate", text="Alternate Select", icon='BORDER_LASSO') # SW - Edit Tools col = pie.column() @@ -544,7 +404,7 @@ class GPENCIL_MT_pie_settings_palette(Menu): pie = layout.menu_pie() gpd = context.gpencil_data gpl = context.active_gpencil_layer - palcolor = context.active_gpencil_palettecolor + palcolor = None # context.active_gpencil_palettecolor brush = context.active_gpencil_brush is_editmode = bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes) @@ -646,7 +506,7 @@ class GPENCIL_MT_pie_tools_more(Menu): class GPENCIL_MT_pie_sculpt(Menu): - """A pie menu for accessing Grease Pencil stroke sculpting settings""" + """A pie menu for accessing Grease Pencil stroke sculpt settings""" bl_label = "Grease Pencil Sculpt" @classmethod @@ -695,9 +555,6 @@ class GPENCIL_MT_pie_sculpt(Menu): row.prop_enum(settings, "tool", value='RANDOMIZE') -############################### - - class GPENCIL_MT_snap(Menu): bl_label = "Snap" @@ -706,7 +563,7 @@ class GPENCIL_MT_snap(Menu): layout.operator("gpencil.snap_to_grid", text="Selection to Grid") layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor").use_offset = False - layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor (Offset)").use_offset = True + layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor (Keep Offset)").use_offset = True layout.separator() @@ -715,8 +572,18 @@ class GPENCIL_MT_snap(Menu): layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid") -class GPENCIL_MT_gpencil_edit_specials(Menu): - bl_label = "GPencil Specials" +class GPENCIL_MT_separate(Menu): + bl_label = "Separate" + + def draw(self, context): + layout = self.layout + layout.operator("gpencil.stroke_separate", text="Selected Points").mode = 'POINT' + layout.operator("gpencil.stroke_separate", text="Selected Strokes").mode = 'STROKE' + layout.operator("gpencil.stroke_separate", text="Active Layer").mode = 'LAYER' + + +class GPENCIL_MT_gpencil_draw_specials(Menu): + bl_label = "GPencil Draw Specials" def draw(self, context): layout = self.layout @@ -724,176 +591,91 @@ class GPENCIL_MT_gpencil_edit_specials(Menu): layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL' layout.separator() + layout.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE' + layout.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX' + layout.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE' - layout.operator("gpencil.stroke_join", text="Join").type = 'JOIN' - layout.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY' - layout.operator("gpencil.stroke_flip", text="Flip Direction") + # Colors. + layout.separator() + layout.operator("gpencil.colorpick", text="Colors", icon="GROUP_VCOL") - if is_3d_view: - layout.separator() - layout.operator("gpencil.reproject") +class GPENCIL_MT_gpencil_draw_delete(Menu): + bl_label = "GPencil Draw Delete" -############################### + def draw(self, context): + layout = self.layout + is_3d_view = context.space_data.type == 'VIEW_3D' + layout.operator_context = 'INVOKE_REGION_WIN' -class GPENCIL_UL_brush(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.GPencilBrush) - brush = item + layout.operator("gpencil.active_frames_delete_all", text="Delete Frame") - if self.layout_type in {'DEFAULT', 'COMPACT'}: - row = layout.row(align=True) - row.prop(brush, "name", text="", emboss=False, icon='BRUSH_DATA') - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) - -class GPENCIL_UL_palettecolor(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.PaletteColor) - palcolor = item - - if self.layout_type in {'DEFAULT', 'COMPACT'}: - if palcolor.lock: - layout.active = False - - split = layout.split(percentage=0.25) - row = split.row(align=True) - row.enabled = not palcolor.lock - row.prop(palcolor, "color", text="", emboss=palcolor.is_stroke_visible) - row.prop(palcolor, "fill_color", text="", emboss=palcolor.is_fill_visible) - split.prop(palcolor, "name", text="", emboss=False) - - row = layout.row(align=True) - row.prop(palcolor, "lock", text="", emboss=False) - row.prop(palcolor, "hide", text="", emboss=False) - if palcolor.ghost is True: - icon = 'GHOST_DISABLED' - else: - icon = 'GHOST_ENABLED' - row.prop(palcolor, "ghost", text="", icon=icon, emboss=False) - - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) - - -class GPENCIL_UL_layer(UIList): +class GPENCIL_UL_annotation_layer(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): # assert(isinstance(item, bpy.types.GPencilLayer) gpl = item + gpd = context.gpencil_data if self.layout_type in {'DEFAULT', 'COMPACT'}: if gpl.lock: layout.active = False - row = layout.row(align=True) - if gpl.is_parented: - icon = 'BONE_DATA' - else: - icon = 'BLANK1' - - row.label(text="", icon=icon) - row.prop(gpl, "info", text="", emboss=False) + split = layout.split(percentage=0.2) + split.prop(gpl, "color", text="", emboss=True) + split.prop(gpl, "info", text="", emboss=False) row = layout.row(align=True) - row.prop(gpl, "lock", text="", emboss=False) + # row.prop(gpl, "lock", text="", emboss=False) row.prop(gpl, "hide", text="", emboss=False) - row.prop(gpl, "unlock_color", text="", emboss=False) elif self.layout_type == 'GRID': layout.alignment = 'CENTER' layout.label(text="", icon_value=icon) -class GPENCIL_MT_layer_specials(Menu): - bl_label = "Layer" - - def draw(self, context): - layout = self.layout - - layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon - - layout.separator() - - layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All") - layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True - - layout.separator() - - layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All") - layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All") - - layout.separator() - - layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down") - - -class GPENCIL_MT_brush_specials(Menu): - bl_label = "Layer" - - def draw(self, context): - layout = self.layout - layout.operator("gpencil.brush_copy", icon='PASTEDOWN', text="Copy Current Drawing Brush") - layout.operator("gpencil.brush_presets_create", icon='HELP', text="Create a Set of Predefined Brushes") - - -class GPENCIL_MT_palettecolor_specials(Menu): - bl_label = "Layer" - - def draw(self, context): - layout = self.layout - - layout.operator("gpencil.palettecolor_reveal", icon='RESTRICT_VIEW_OFF', text="Show All") - layout.operator("gpencil.palettecolor_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True - - layout.separator() - - layout.operator("gpencil.palettecolor_lock_all", icon='LOCKED', text="Lock All") - layout.operator("gpencil.palettecolor_unlock_all", icon='UNLOCKED', text="UnLock All") - layout.operator("gpencil.palettecolor_copy", icon='PASTEDOWN', text="Copy Color") - - layout.separator() - - layout.operator("gpencil.palettecolor_select", icon='COLOR', text="Select Strokes") - layout.operator("gpencil.stroke_change_color", icon='MAN_TRANS', text="Move to Color") - - class GreasePencilDataPanel: - # subclass must set - # bl_space_type = 'IMAGE_EDITOR' - bl_label = "Grease Pencil Layers" + bl_label = "Annotations" bl_region_type = 'UI' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + # Show this panel as long as someone that might own this exists + # AND the owner isn't an object (e.g. GP Object) + if context.gpencil_data_owner is None: + return False + elif type(context.gpencil_data_owner) is bpy.types.Object: + return False + else: + return True @staticmethod def draw_header(self, context): - self.layout.prop(context.space_data, "show_grease_pencil", text="") + if context.space_data.type != 'VIEW_3D': + self.layout.prop(context.space_data, "show_annotation", text="") @staticmethod def draw(self, context): layout = self.layout + layout.use_property_decorate = False - # owner of Grease Pencil data + # Grease Pencil owner. gpd_owner = context.gpencil_data_owner gpd = context.gpencil_data - # Owner Selector - if context.space_data.type == 'VIEW_3D': - layout.row().prop(context.tool_settings, "grease_pencil_source", expand=True) - elif context.space_data.type == 'CLIP_EDITOR': + # Owner selector. + if context.space_data.type == 'CLIP_EDITOR': layout.row().prop(context.space_data, "grease_pencil_source", expand=True) - # Grease Pencil data selector layout.template_ID(gpd_owner, "grease_pencil", new="gpencil.data_add", unlink="gpencil.data_unlink") - # Grease Pencil data... - if (gpd is None) or (not gpd.layers): - layout.operator("gpencil.layer_add", text="New Layer") - else: + # List of layers/notes. + if gpd and gpd.layers: self.draw_layers(context, layout, gpd) def draw_layers(self, context, layout, gpd): @@ -904,7 +686,7 @@ class GreasePencilDataPanel: layer_rows = 5 else: layer_rows = 2 - col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows) + col.template_list("GPENCIL_UL_annotation_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows) col = row.column() @@ -914,8 +696,6 @@ class GreasePencilDataPanel: gpl = context.active_gpencil_layer if gpl: - sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="") - if len(gpd.layers) > 1: col.separator() @@ -923,211 +703,72 @@ class GreasePencilDataPanel: 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_OFF', text="").affect_visibility = True - - if gpl: - self.draw_layer(context, layout, gpl) - - def draw_layer(self, context, layout, gpl): - row = layout.row(align=True) - row.prop(gpl, "opacity", text="Opacity", slider=True) - - # Layer options - split = layout.split(percentage=0.5) - split.active = not gpl.lock - split.prop(gpl, "show_x_ray") - split.prop(gpl, "show_points") - - # Offsets + Parenting (where available) - if context.space_data.type == 'VIEW_3D': - split = layout.split(percentage=0.5) - else: - split = layout.column() # parenting is not available in 2D editors... - split.active = not gpl.lock - - # Offsets - Color Tint - col = split.column() - subcol = col.column(align=True) - subcol.label("Tint") - subcol.enabled = not gpl.lock - subcol.prop(gpl, "tint_color", text="") - subcol.prop(gpl, "tint_factor", text="Factor", slider=True) - - # Offsets - Thickness - row = col.row(align=True) - row.prop(gpl, "line_change", text="Thickness Change", slider=True) - row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="") - - # Parenting - if context.space_data.type == 'VIEW_3D': - col = split.column(align=True) - col.label(text="Parent:") - col.prop(gpl, "parent", text="") - - sub = col.column() - sub.prop(gpl, "parent_type", text="") - parent = gpl.parent - if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE': - sub.prop_search(gpl, "parent_bone", parent.data, "bones", text="") - - layout.separator() - - # Full-Row - Frame Locking (and Delete Frame) - row = layout.row(align=True) - row.active = not gpl.lock - - if gpl.active_frame: - lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked") - lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status) + tool_settings = context.tool_settings + if gpd and gpl: + layout.prop(gpl, "thickness") else: - lock_label = iface_("Lock Frame") - row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED') - row.operator("gpencil.active_frame_delete", text="", icon='X') - - layout.separator() + layout.prop(tool_settings, "annotation_thickness", text="Thickness") - # Onion skinning - col = layout.column(align=True) - col.active = not gpl.lock + if gpl: + # layout.prop(gpl, "opacity", text="Opacity", slider=True) + # Full-Row - Frame Locking (and Delete Frame) + row = layout.row(align=True) + row.active = not gpl.lock - row = col.row() - row.prop(gpl, "use_onion_skinning") - sub = row.row(align=True) - icon = 'RESTRICT_RENDER_OFF' if gpl.use_ghosts_always else 'RESTRICT_RENDER_ON' - sub.prop(gpl, "use_ghosts_always", text="", icon=icon) - sub.prop(gpl, "use_ghost_custom_colors", text="", icon='COLOR') - - split = col.split(percentage=0.5) - split.active = gpl.use_onion_skinning - - # - Before Frames - sub = split.column(align=True) - row = sub.row(align=True) - row.active = gpl.use_ghost_custom_colors - row.prop(gpl, "before_color", text="") - sub.prop(gpl, "ghost_before_range", text="Before") - - # - After Frames - sub = split.column(align=True) - row = sub.row(align=True) - row.active = gpl.use_ghost_custom_colors - row.prop(gpl, "after_color", text="") - sub.prop(gpl, "ghost_after_range", text="After") - - -class GreasePencilPaletteColorPanel: - # subclass must set - bl_label = "Grease Pencil Colors" - bl_region_type = 'UI' + if gpl.active_frame: + lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked") + lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status) + else: + lock_label = iface_("Lock Frame") + row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED') + row.operator("gpencil.active_frame_delete", text="", icon='X') - @classmethod - def poll(cls, context): - if context.gpencil_data is None: - return False - gpd = context.gpencil_data - return bool(gpd.layers.active) +class GreasePencilOnionPanel: @staticmethod - def draw(self, context): - layout = self.layout - palette = context.active_gpencil_palette - - if palette: - row = layout.row(align=True) - row.operator_context = 'EXEC_REGION_WIN' - row.operator_menu_enum("gpencil.palette_change", "palette", text="", icon='COLOR') - row.prop(palette, "name", text="") - row.operator("gpencil.palette_add", icon='ZOOMIN', text="") - row.operator("gpencil.palette_remove", icon='X', text="") - - # Palette colors - row = layout.row() - col = row.column() - if len(palette.colors) >= 2: - color_rows = 5 - else: - color_rows = 2 - col.template_list("GPENCIL_UL_palettecolor", "", palette, "colors", palette.colors, "active_index", - rows=color_rows) + def draw_settings(layout, gp): + col = layout.column() + col.prop(gp, "onion_mode") + col.prop(gp, "onion_factor", text="Opacity", slider=True) - col = row.column() + if gp.onion_mode in ('ABSOLUTE', 'RELATIVE'): + col = layout.column(align=True) + col.prop(gp, "ghost_before_range", text="Frames Before") + col.prop(gp, "ghost_after_range", text="After") - sub = col.column(align=True) - sub.operator("gpencil.palettecolor_add", icon='ZOOMIN', text="") - sub.operator("gpencil.palettecolor_remove", icon='ZOOMOUT', text="") + layout.prop(gp, "use_ghost_custom_colors", text="Use Custom Colors") - palcol = context.active_gpencil_palettecolor - if palcol: - sub.menu("GPENCIL_MT_palettecolor_specials", icon='DOWNARROW_HLT', text="") + if gp.use_ghost_custom_colors: + col = layout.column(align=True) + col.active = gp.use_ghost_custom_colors + col.prop(gp, "before_color", text="Color Before") + col.prop(gp, "after_color", text="After") - if len(palette.colors) > 1: - col.separator() + layout.prop(gp, "use_ghosts_always", text="View In Render") - sub = col.column(align=True) - sub.operator("gpencil.palettecolor_move", icon='TRIA_UP', text="").direction = 'UP' - sub.operator("gpencil.palettecolor_move", icon='TRIA_DOWN', text="").direction = 'DOWN' - - row = layout.row() - sub = row.row(align=True) - sub.label(text="Isolate:") # based on active color only - sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False - sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True - sub = row.row(align=True) - sub.label(text="Lock:") # based on other stuff... - sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="") - sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="") - - pcolor = palette.colors.active - if pcolor: - self.draw_palettecolors(layout, pcolor) - - # Draw palette colors - def draw_palettecolors(self, layout, pcolor): - # color settings - split = layout.split(percentage=0.5) - split.active = not pcolor.lock - - # Column 1 - Stroke - col = split.column(align=True) - col.enabled = not pcolor.lock - col.label(text="Stroke:") - col.prop(pcolor, "color", text="") - col.prop(pcolor, "alpha", slider=True) - - # Column 2 - Fill - col = split.column(align=True) - col.enabled = not pcolor.lock - col.label(text="Fill:") - col.prop(pcolor, "fill_color", text="") - col.prop(pcolor, "fill_alpha", text="Opacity", slider=True) - - # Options - split = layout.split(percentage=0.5) - split.active = not pcolor.lock - - col = split.column(align=True) - col.active = not pcolor.lock - col.prop(pcolor, "use_volumetric_strokes") - col = split.column(align=True) - col.active = not pcolor.lock - col.prop(pcolor, "use_hq_fill") + col = layout.column(align=True) + col.active = gp.use_onion_skinning + col.prop(gp, "use_onion_fade", text="Fade") + if hasattr(gp, "use_onion_loop"): # XXX + sub = layout.column() + sub.active = gp.onion_mode in ('RELATIVE', 'SELECTED') + sub.prop(gp, "use_onion_loop", text="Loop") class GreasePencilToolsPanel: # For use in "2D" Editors without their own toolbar # subclass must set # bl_space_type = 'IMAGE_EDITOR' - # bl_options = {'DEFAULT_CLOSED'} bl_label = "Grease Pencil Settings" bl_region_type = 'UI' + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): + # XXX - disabled in 2.8 branch. + return False + return (context.gpencil_data is not None) @staticmethod @@ -1161,14 +802,14 @@ classes = ( GPENCIL_MT_pie_settings_palette, GPENCIL_MT_pie_tools_more, GPENCIL_MT_pie_sculpt, + GPENCIL_MT_snap, - GPENCIL_MT_gpencil_edit_specials, - GPENCIL_UL_brush, - GPENCIL_UL_palettecolor, - GPENCIL_UL_layer, - GPENCIL_MT_layer_specials, - GPENCIL_MT_brush_specials, - GPENCIL_MT_palettecolor_specials, + GPENCIL_MT_separate, + + GPENCIL_MT_gpencil_draw_specials, + GPENCIL_MT_gpencil_draw_delete, + + GPENCIL_UL_annotation_layer, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index 450ca80bbc2..c766c8dedbc 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -378,6 +378,12 @@ class MASK_MT_select(Menu): def draw(self, context): layout = self.layout + layout.operator("mask.select_all", text="All").action = 'SELECT' + layout.operator("mask.select_all", text="None").action = 'DESELECT' + layout.operator("mask.select_all", text="Invert").action = 'INVERT' + + layout.separator() + layout.operator("mask.select_border") layout.operator("mask.select_circle") @@ -388,8 +394,6 @@ class MASK_MT_select(Menu): layout.separator() - layout.operator("mask.select_all").action = 'TOGGLE' - layout.operator("mask.select_all", text="Inverse").action = 'INVERT' layout.operator("mask.select_linked", text="Select Linked") diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 73740df37e8..706ce497dee 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -21,42 +21,7 @@ import bpy from bpy.types import Menu, Panel, UIList from rna_prop_ui import PropertyPanel from bpy.app.translations import pgettext_iface as iface_ - - -def active_node_mat(mat): - # TODO, 2.4x has a pipeline section, for 2.5 we need to communicate - # which settings from node-materials are used - if mat is not None: - mat_node = mat.active_node_material - if mat_node: - return mat_node - else: - return mat - - return None - - -def check_material(mat): - if mat is not None: - if mat.use_nodes: - if mat.active_node_material is not None: - return True - return False - return True - return False - - -def simple_material(mat): - if (mat is not None) and (not mat.use_nodes): - return True - return False - - -class MATERIAL_MT_sss_presets(Menu): - bl_label = "SSS Presets" - preset_subdir = "sss" - preset_operator = "script.execute_preset" - draw = Menu.draw_preset +from bpy_extras.node_utils import find_node_input class MATERIAL_MT_specials(Menu): @@ -82,12 +47,6 @@ class MATERIAL_UL_matslots(UIList): layout.prop(ma, "name", text="", emboss=False, icon_value=icon) else: layout.label(text="", icon_value=icon) - if ma and not context.scene.render.use_shading_nodes: - manode = ma.active_node_material - if manode: - layout.label(text=iface_("Node %s") % manode.name, translate=False, icon_value=layout.icon(manode)) - elif ma.use_nodes: - layout.label(text="Node <none>") elif self.layout_type == 'GRID': layout.alignment = 'CENTER' layout.label(text="", icon_value=icon) @@ -101,21 +60,37 @@ class MaterialButtonsPanel: @classmethod def poll(cls, context): - return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES) + return context.material and (context.engine in cls.COMPAT_ENGINES) + + +class MATERIAL_PT_preview(MaterialButtonsPanel, Panel): + bl_label = "Preview" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + self.layout.template_preview(context.material) + + +class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_OPENGL'} + _context_path = "material" + _property_type = bpy.types.Material -class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): +class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): bl_label = "" + bl_context = "material" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - # An exception, don't call the parent poll func because - # this manages materials for all engine types - - engine = context.scene.render.engine - return (context.material or context.object) and (engine in cls.COMPAT_ENGINES) + if context.active_object and context.active_object.type == 'GPENCIL': + return False + else: + engine = context.engine + return (context.material or context.object) and (engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout @@ -126,10 +101,9 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): space = context.space_data if ob: - is_sortable = (len(ob.material_slots) > 1) - - rows = 1 - if is_sortable: + is_sortable = len(ob.material_slots) > 1 + rows = 2 + if (is_sortable): rows = 4 row = layout.row() @@ -148,943 +122,132 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): 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="material.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") - split = layout.split(percentage=0.65) - - if ob: - split.template_ID(ob, "active_material", new="material.new") - row = split.row() - if mat: - row.prop(mat, "use_nodes", icon='NODETREE', text="") - - if slot: - row.prop(slot, "link", text="") - else: - row.label() elif mat: - split.template_ID(space, "pin_id") - split.separator() - - if mat: - layout.row().prop(mat, "type", expand=True) - if mat.use_nodes: - row = layout.row() - row.label(text="", icon='NODETREE') - if mat.active_node_material: - row.prop(mat.active_node_material, "name", text="") - else: - row.label(text="No material node selected") - - -class MATERIAL_PT_preview(MaterialButtonsPanel, Panel): - bl_label = "Preview" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - def draw(self, context): - self.layout.template_preview(context.material) - - -class MATERIAL_PT_pipeline(MaterialButtonsPanel, Panel): - bl_label = "Render Pipeline Options" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return mat and (not simple_material(mat)) and (mat.type in {'SURFACE', 'WIRE', 'VOLUME'}) and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self. layout - - mat = context.material - mat_type = mat.type in {'SURFACE', 'WIRE'} - - row = layout.row() - row.active = mat_type - row.prop(mat, "use_transparency") - sub = row.column() - sub.prop(mat, "offset_z") - - sub.active = mat_type and mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY' - - row = layout.row() - row.active = mat.use_transparency or not mat_type - row.prop(mat, "transparency_method", expand=True) - - layout.separator() - - split = layout.split() - col = split.column() - - col.prop(mat, "use_raytrace") - col.prop(mat, "use_full_oversampling") - sub = col.column() - sub.active = mat_type - sub.prop(mat, "use_sky") - sub.prop(mat, "invert_z") - col.prop(mat, "pass_index") - - col = split.column() - col.active = mat_type - - col.prop(mat, "use_cast_shadows", text="Cast") - col.prop(mat, "use_cast_shadows_only", text="Cast Only") - col.prop(mat, "use_cast_buffer_shadows") - sub = col.column() - sub.active = mat.use_cast_buffer_shadows - sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha") - col.prop(mat, "use_cast_approximate") - - -class MATERIAL_PT_diffuse(MaterialButtonsPanel, Panel): - bl_label = "Diffuse" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - mat = active_node_mat(context.material) - - split = layout.split() - - col = split.column() - col.prop(mat, "diffuse_color", text="") - sub = col.column() - sub.active = (not mat.use_shadeless) - sub.prop(mat, "diffuse_intensity", text="Intensity") - - col = split.column() - col.active = (not mat.use_shadeless) - col.prop(mat, "diffuse_shader", text="") - col.prop(mat, "use_diffuse_ramp", text="Ramp") - - col = layout.column() - col.active = (not mat.use_shadeless) - if mat.diffuse_shader == 'OREN_NAYAR': - col.prop(mat, "roughness") - elif mat.diffuse_shader == 'MINNAERT': - col.prop(mat, "darkness") - elif mat.diffuse_shader == 'TOON': - row = col.row() - row.prop(mat, "diffuse_toon_size", text="Size") - row.prop(mat, "diffuse_toon_smooth", text="Smooth") - elif mat.diffuse_shader == 'FRESNEL': - row = col.row() - row.prop(mat, "diffuse_fresnel", text="Fresnel") - row.prop(mat, "diffuse_fresnel_factor", text="Factor") - - if mat.use_diffuse_ramp: - col = layout.column() - col.active = (not mat.use_shadeless) - col.separator() - col.template_color_ramp(mat, "diffuse_ramp", expand=True) - col.separator() - - row = col.row() - row.prop(mat, "diffuse_ramp_input", text="Input") - row.prop(mat, "diffuse_ramp_blend", text="Blend") - - col.prop(mat, "diffuse_ramp_factor", text="Factor") - - -class MATERIAL_PT_specular(MaterialButtonsPanel, Panel): - bl_label = "Specular" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - mat = active_node_mat(context.material) - - layout.active = (not mat.use_shadeless) - - split = layout.split() - - col = split.column() - col.prop(mat, "specular_color", text="") - col.prop(mat, "specular_intensity", text="Intensity") - - col = split.column() - col.prop(mat, "specular_shader", text="") - col.prop(mat, "use_specular_ramp", text="Ramp") - - col = layout.column() - if mat.specular_shader in {'COOKTORR', 'PHONG'}: - col.prop(mat, "specular_hardness", text="Hardness") - elif mat.specular_shader == 'BLINN': - row = col.row() - row.prop(mat, "specular_hardness", text="Hardness") - row.prop(mat, "specular_ior", text="IOR") - elif mat.specular_shader == 'WARDISO': - col.prop(mat, "specular_slope", text="Slope") - elif mat.specular_shader == 'TOON': - row = col.row() - row.prop(mat, "specular_toon_size", text="Size") - row.prop(mat, "specular_toon_smooth", text="Smooth") - - if mat.use_specular_ramp: - layout.separator() - layout.template_color_ramp(mat, "specular_ramp", expand=True) - layout.separator() - - row = layout.row() - row.prop(mat, "specular_ramp_input", text="Input") - row.prop(mat, "specular_ramp_blend", text="Blend") - - layout.prop(mat, "specular_ramp_factor", text="Factor") - - -class MATERIAL_PT_shading(MaterialButtonsPanel, Panel): - bl_label = "Shading" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - mat = active_node_mat(context.material) - - if mat.type in {'SURFACE', 'WIRE'}: - split = layout.split() - - col = split.column() - sub = col.column() - sub.active = not mat.use_shadeless - sub.prop(mat, "emit") - sub.prop(mat, "ambient") - sub = col.column() - sub.prop(mat, "translucency") - - col = split.column() - col.prop(mat, "use_shadeless") - sub = col.column() - sub.active = not mat.use_shadeless - sub.prop(mat, "use_tangent_shading") - sub.prop(mat, "use_cubic") - - -class MATERIAL_PT_transp(MaterialButtonsPanel, Panel): - bl_label = "Transparency" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - mat = context.material - - if simple_material(mat): - self.layout.prop(mat, "use_transparency", text="") - - def draw(self, context): - layout = self.layout - - base_mat = context.material - mat = active_node_mat(context.material) - rayt = mat.raytrace_transparency - - if simple_material(base_mat): - row = layout.row() - row.active = mat.use_transparency - row.prop(mat, "transparency_method", expand=True) - - split = layout.split() - split.active = base_mat.use_transparency - - col = split.column() - col.prop(mat, "alpha") - row = col.row() - row.active = (base_mat.transparency_method != 'MASK') and (not mat.use_shadeless) - row.prop(mat, "specular_alpha", text="Specular") - - col = split.column() - col.active = (not mat.use_shadeless) - col.prop(rayt, "fresnel") - sub = col.column() - sub.active = (rayt.fresnel > 0.0) - sub.prop(rayt, "fresnel_factor", text="Blend") - - if base_mat.transparency_method == 'RAYTRACE': - layout.separator() - split = layout.split() - split.active = base_mat.use_transparency - - col = split.column() - col.prop(rayt, "ior") - col.prop(rayt, "filter") - col.prop(rayt, "falloff") - col.prop(rayt, "depth_max") - col.prop(rayt, "depth") - - col = split.column() - col.label(text="Gloss:") - col.prop(rayt, "gloss_factor", text="Amount") - sub = col.column() - sub.active = rayt.gloss_factor < 1.0 - sub.prop(rayt, "gloss_threshold", text="Threshold") - sub.prop(rayt, "gloss_samples", text="Samples") - - -class MATERIAL_PT_mirror(MaterialButtonsPanel, Panel): - bl_label = "Mirror" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - raym = active_node_mat(context.material).raytrace_mirror - - self.layout.prop(raym, "use", text="") - - def draw(self, context): - layout = self.layout - - mat = active_node_mat(context.material) - raym = mat.raytrace_mirror - - layout.active = raym.use - - split = layout.split() - - col = split.column() - col.prop(raym, "reflect_factor") - col.prop(mat, "mirror_color", text="") - - col = split.column() - col.prop(raym, "fresnel") - sub = col.column() - sub.active = (raym.fresnel > 0.0) - sub.prop(raym, "fresnel_factor", text="Blend") - - split = layout.split() - - col = split.column() - col.separator() - col.prop(raym, "depth") - col.prop(raym, "distance", text="Max Dist") - col.separator() - sub = col.split(percentage=0.4) - sub.active = (raym.distance > 0.0) - sub.label(text="Fade To:") - sub.prop(raym, "fade_to", text="") - - col = split.column() - col.label(text="Gloss:") - col.prop(raym, "gloss_factor", text="Amount") - sub = col.column() - sub.active = (raym.gloss_factor < 1.0) - sub.prop(raym, "gloss_threshold", text="Threshold") - sub.prop(raym, "gloss_samples", text="Samples") - sub.prop(raym, "gloss_anisotropic", text="Anisotropic") - - -class MATERIAL_PT_sss(MaterialButtonsPanel, Panel): - bl_label = "Subsurface Scattering" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - mat = active_node_mat(context.material) - sss = mat.subsurface_scattering - - self.layout.active = (not mat.use_shadeless) - self.layout.prop(sss, "use", text="") - - def draw(self, context): - layout = self.layout + row.template_ID(space, "pin_id") - mat = active_node_mat(context.material) - sss = mat.subsurface_scattering - layout.active = (sss.use) and (not mat.use_shadeless) - - row = layout.row().split() - sub = row.row(align=True).split(align=True, percentage=0.75) - sub.menu("MATERIAL_MT_sss_presets", text=bpy.types.MATERIAL_MT_sss_presets.bl_label) - sub.operator("material.sss_preset_add", text="", icon='ZOOMIN') - sub.operator("material.sss_preset_add", text="", icon='ZOOMOUT').remove_active = True - - split = layout.split() - - col = split.column() - col.prop(sss, "ior") - col.prop(sss, "scale") - col.prop(sss, "color", text="") - col.prop(sss, "radius", text="RGB Radius", expand=True) - - col = split.column() - sub = col.column(align=True) - sub.label(text="Blend:") - sub.prop(sss, "color_factor", text="Color") - sub.prop(sss, "texture_factor", text="Texture") - sub.label(text="Scattering Weight:") - sub.prop(sss, "front") - sub.prop(sss, "back") - col.separator() - col.prop(sss, "error_threshold", text="Error") - - -class MATERIAL_PT_halo(MaterialButtonsPanel, Panel): - bl_label = "Halo" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - mat = context.material # don't use node material - halo = mat.halo - - def number_but(layout, toggle, number, name, color): - row = layout.row(align=True) - row.prop(halo, toggle, text="") - sub = row.column(align=True) - sub.active = getattr(halo, toggle) - sub.prop(halo, number, text=name, translate=False) - if not color == "": - sub.prop(mat, color, text="") - - split = layout.split() - - col = split.column() - col.prop(mat, "alpha") - col.prop(mat, "diffuse_color", text="") - col.prop(halo, "seed") - - col = split.column() - col.prop(halo, "size") - col.prop(halo, "hardness") - col.prop(halo, "add") - - layout.label(text="Options:") - - split = layout.split() - col = split.column() - col.prop(halo, "use_texture") - col.prop(halo, "use_vertex_normal") - col.prop(halo, "use_extreme_alpha") - col.prop(halo, "use_shaded") - col.prop(halo, "use_soft") - - col = split.column() - number_but(col, "use_ring", "ring_count", iface_("Rings"), "mirror_color") - number_but(col, "use_lines", "line_count", iface_("Lines"), "specular_color") - number_but(col, "use_star", "star_tip_count", iface_("Star Tips"), "") - - -class MATERIAL_PT_flare(MaterialButtonsPanel, Panel): - bl_label = "Flare" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return mat and (mat.type == 'HALO') and (engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - halo = context.material.halo - - self.layout.prop(halo, "use_flare_mode", text="") - - def draw(self, context): - layout = self.layout - - mat = context.material # don't use node material - halo = mat.halo - - layout.active = halo.use_flare_mode - - split = layout.split() - - col = split.column() - col.prop(halo, "flare_size", text="Size") - col.prop(halo, "flare_boost", text="Boost") - col.prop(halo, "flare_seed", text="Seed") - - col = split.column() - col.prop(halo, "flare_subflare_count", text="Subflares") - col.prop(halo, "flare_subflare_size", text="Subsize") - - -class MATERIAL_PT_game_settings(MaterialButtonsPanel, Panel): - bl_label = "Game Settings" - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - game = context.material.game_settings # don't use node material - - row = layout.row() - row.prop(game, "use_backface_culling") - row.prop(game, "invisible") - row.prop(game, "text") - - row = layout.row() - row.label(text="Alpha Blend:") - row.label(text="Face Orientation:") - row = layout.row() - row.prop(game, "alpha_blend", text="") - row.prop(game, "face_orientation", text="") +def panel_node_draw(layout, ntree, output_type): + node = ntree.get_output_node('EEVEE') + if node: + input = find_node_input(node, 'Surface') + if input: + layout.template_node_view(ntree, node, input) + else: + layout.label(text="Incompatible output node") + else: + layout.label(text="No output node") -class MATERIAL_PT_physics(MaterialButtonsPanel, Panel): - bl_label = "Physics" - COMPAT_ENGINES = {'BLENDER_GAME'} - def draw_header(self, context): - game = context.material.game_settings - self.layout.prop(game, "physics", text="") +class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel): + bl_label = "Surface" + bl_context = "material" + COMPAT_ENGINES = {'BLENDER_EEVEE'} @classmethod def poll(cls, context): - return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES) + engine = context.engine + return context.material and (engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout - layout.active = context.material.game_settings.physics - - phys = context.material.physics # don't use node material - - split = layout.split() - row = split.row() - row.prop(phys, "friction") - row.prop(phys, "elasticity", slider=True) - - row = layout.row() - row.label(text="Force Field:") - - row = layout.row() - row.prop(phys, "fh_force") - row.prop(phys, "fh_damping", slider=True) - - row = layout.row() - row.prop(phys, "fh_distance") - row.prop(phys, "use_fh_normal") - -class MATERIAL_PT_strand(MaterialButtonsPanel, Panel): - bl_label = "Strand" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): mat = context.material - engine = context.scene.render.engine - return mat and (mat.type in {'SURFACE', 'WIRE', 'HALO'}) and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - mat = context.material # don't use node material - tan = mat.strand - split = layout.split() - - col = split.column() - sub = col.column(align=True) - sub.label(text="Size:") - sub.prop(tan, "root_size", text="Root") - sub.prop(tan, "tip_size", text="Tip") - sub.prop(tan, "size_min", text="Minimum") - sub.prop(tan, "use_blender_units") - sub = col.column() - sub.active = (not mat.use_shadeless) - sub.prop(tan, "use_tangent_shading") - col.prop(tan, "shape") + layout.prop(mat, "use_nodes", icon='NODETREE') + layout.separator() - col = split.column() - col.label(text="Shading:") - col.prop(tan, "width_fade") - ob = context.object - if ob and ob.type == 'MESH': - col.prop_search(tan, "uv_layer", ob.data, "uv_textures", text="") + if mat.use_nodes: + panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL') else: - col.prop(tan, "uv_layer", text="") - col.separator() - sub = col.column() - sub.active = (not mat.use_shadeless) - sub.label("Surface diffuse:") - sub = col.column() - sub.prop(tan, "blend_distance", text="Distance") + layout.use_property_split = True + layout.prop(mat, "diffuse_color", text="Base Color") + layout.prop(mat, "metallic") + layout.prop(mat, "specular_intensity", text="Specular") + layout.prop(mat, "roughness") -class MATERIAL_PT_options(MaterialButtonsPanel, Panel): +class EEVEE_MATERIAL_PT_options(MaterialButtonsPanel, Panel): bl_label = "Options" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_context = "material" + COMPAT_ENGINES = {'BLENDER_EEVEE'} @classmethod def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) + engine = context.engine + return context.material and (engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True - base_mat = context.material - mat = active_node_mat(base_mat) - - split = layout.split() - - col = split.column() - if simple_material(base_mat): - col.prop(mat, "use_raytrace") - col.prop(mat, "use_full_oversampling") - col.prop(mat, "use_sky") - col.prop(mat, "use_mist") - if simple_material(base_mat): - col.prop(mat, "invert_z") - sub = col.row() - sub.prop(mat, "offset_z") - sub.active = mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY' - sub = col.column(align=True) - sub.label(text="Light Group:") - sub.prop(mat, "light_group", text="") - row = sub.row(align=True) - row.active = bool(mat.light_group) - row.prop(mat, "use_light_group_exclusive", text="Exclusive") - row.prop(mat, "use_light_group_local", text="Local") - - col = split.column() - col.prop(mat, "use_face_texture") - sub = col.column() - sub.active = mat.use_face_texture - sub.prop(mat, "use_face_texture_alpha") - col.separator() - col.prop(mat, "use_vertex_color_paint") - col.prop(mat, "use_vertex_color_light") - col.prop(mat, "use_object_color") - col.prop(mat, "use_uv_project") - if simple_material(base_mat): - col.prop(mat, "pass_index") - - -class MATERIAL_PT_shadow(MaterialButtonsPanel, Panel): - bl_label = "Shadow" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - - base_mat = context.material - mat = active_node_mat(base_mat) - split = layout.split() + layout.prop(mat, "blend_method") - col = split.column() - col.prop(mat, "use_shadows", text="Receive") - col.prop(mat, "use_transparent_shadows", text="Receive Transparent") - col.prop(mat, "use_only_shadow", text="Shadows Only") - sub = col.column() - sub.active = mat.use_only_shadow - sub.prop(mat, "shadow_only_type", text="") + if mat.blend_method != 'OPAQUE': + layout.prop(mat, "transparent_shadow_method") - if not simple_material(base_mat): - col = split.column() - - col.prop(mat, "use_ray_shadow_bias", text="Auto Ray Bias") - sub = col.column() - sub.active = (not mat.use_ray_shadow_bias) - sub.prop(mat, "shadow_ray_bias", text="Ray Bias") - - if simple_material(base_mat): - col = split.column() - - col.prop(mat, "use_cast_shadows", text="Cast") - col.prop(mat, "use_cast_shadows_only", text="Cast Only") - col.prop(mat, "use_cast_buffer_shadows") - sub = col.column() - sub.active = mat.use_cast_buffer_shadows - if simple_material(base_mat): - sub.prop(mat, "shadow_cast_alpha", text="Casting Alpha") - sub.prop(mat, "shadow_buffer_bias", text="Buffer Bias") - if simple_material(base_mat): - col.prop(mat, "use_cast_approximate") - - -class MATERIAL_PT_transp_game(MaterialButtonsPanel, Panel): - bl_label = "Transparency" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - mat = context.material - - if simple_material(mat): - self.layout.prop(mat, "use_transparency", text="") - - def draw(self, context): - layout = self.layout - base_mat = context.material - mat = active_node_mat(base_mat) - - layout.active = mat.use_transparency - - if simple_material(base_mat): row = layout.row() - row.prop(mat, "transparency_method", expand=True) - - layout.prop(mat, "alpha") - layout.prop(mat, "specular_alpha", text="Specular") - - -class VolumeButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "material" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return mat and (mat.type == 'VOLUME') and (engine in cls.COMPAT_ENGINES) - - -class MATERIAL_PT_volume_density(VolumeButtonsPanel, Panel): - bl_label = "Density" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw(self, context): - layout = self.layout - - vol = context.material.volume # don't use node material - - row = layout.row() - row.prop(vol, "density") - row.prop(vol, "density_scale") - - -class MATERIAL_PT_volume_shading(VolumeButtonsPanel, Panel): - bl_label = "Shading" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw(self, context): - layout = self.layout - - vol = context.material.volume # don't use node material - - split = layout.split() - - col = split.column() - col.prop(vol, "scattering") - col.prop(vol, "asymmetry") - col.prop(vol, "transmission_color") + row.active = ((mat.blend_method == 'CLIP') or (mat.transparent_shadow_method == 'CLIP')) + row.prop(mat, "alpha_threshold") - col = split.column() - sub = col.column(align=True) - sub.prop(vol, "emission") - sub.prop(vol, "emission_color", text="") - sub = col.column(align=True) - sub.prop(vol, "reflection") - sub.prop(vol, "reflection_color", text="") + if mat.blend_method not in {'OPAQUE', 'CLIP', 'HASHED'}: + layout.prop(mat, "show_transparent_backside") + layout.prop(mat, "use_screen_refraction") + layout.prop(mat, "refraction_depth") + layout.prop(mat, "use_sss_translucency") -class MATERIAL_PT_volume_lighting(VolumeButtonsPanel, Panel): - bl_label = "Lighting" - COMPAT_ENGINES = {'BLENDER_RENDER'} - def draw(self, context): - layout = self.layout - - vol = context.material.volume # don't use node material - - split = layout.split() - - col = split.column() - col.prop(vol, "light_method", text="") - - col = split.column() - - if vol.light_method == 'SHADED': - col.prop(vol, "use_external_shadows") - col.prop(vol, "use_light_cache") - sub = col.column() - sub.active = vol.use_light_cache - sub.prop(vol, "cache_resolution") - elif vol.light_method in {'MULTIPLE_SCATTERING', 'SHADED_PLUS_MULTIPLE_SCATTERING'}: - sub = col.column() - sub.enabled = True - sub.active = False - sub.label("Light Cache Enabled") - col.prop(vol, "cache_resolution") - - sub = col.column(align=True) - sub.prop(vol, "ms_diffusion") - sub.prop(vol, "ms_spread") - sub.prop(vol, "ms_intensity") - - -class MATERIAL_PT_volume_transp(VolumeButtonsPanel, Panel): - bl_label = "Transparency" - COMPAT_ENGINES = {'BLENDER_RENDER'} +class MATERIAL_PT_viewport(MaterialButtonsPanel, Panel): + bl_label = "Viewport Display" + bl_context = "material" + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): - mat = context.material - engine = context.scene.render.engine - return mat and simple_material(mat) and (mat.type == 'VOLUME') and (engine in cls.COMPAT_ENGINES) + return context.material def draw(self, context): - layout = self.layout - - mat = context.material # don't use node material - - layout.row().prop(mat, "transparency_method", expand=True) - - -class MATERIAL_PT_volume_integration(VolumeButtonsPanel, Panel): - bl_label = "Integration" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw(self, context): - layout = self.layout - - vol = context.material.volume # don't use node material - - split = layout.split() - - col = split.column() - col.label(text="Step Calculation:") - col.prop(vol, "step_method", text="") - col = col.column(align=True) - col.prop(vol, "step_size") - - col = split.column() - col.label() - col.prop(vol, "depth_threshold") - - -class MATERIAL_PT_volume_options(VolumeButtonsPanel, Panel): - bl_label = "Options" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - bl_options = {'DEFAULT_CLOSED'} - - @classmethod - def poll(cls, context): mat = context.material - engine = context.scene.render.engine - return check_material(mat) and (mat.type == 'VOLUME') and (engine in cls.COMPAT_ENGINES) - def draw(self, context): layout = self.layout + layout.use_property_split = True - mat = active_node_mat(context.material) - - split = layout.split() - - col = split.column() - if simple_material(context.material): - col.prop(mat, "use_raytrace") - col.prop(mat, "use_full_oversampling") - col.prop(mat, "use_mist") - - col = split.column() - col.label(text="Light Group:") - col.prop(mat, "light_group", text="") - row = col.row() - row.active = bool(mat.light_group) - row.prop(mat, "use_light_group_exclusive", text="Exclusive") - - -class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - _context_path = "material" - _property_type = bpy.types.Material + col = layout.column() + col.prop(mat, "diffuse_color") + col.prop(mat, "specular_color") + col.prop(mat, "roughness") classes = ( - MATERIAL_MT_sss_presets, MATERIAL_MT_specials, MATERIAL_UL_matslots, - MATERIAL_PT_context_material, MATERIAL_PT_preview, - MATERIAL_PT_pipeline, - MATERIAL_PT_diffuse, - MATERIAL_PT_specular, - MATERIAL_PT_shading, - MATERIAL_PT_transp, - MATERIAL_PT_mirror, - MATERIAL_PT_sss, - MATERIAL_PT_halo, - MATERIAL_PT_flare, - MATERIAL_PT_game_settings, - MATERIAL_PT_physics, - MATERIAL_PT_strand, - MATERIAL_PT_options, - MATERIAL_PT_shadow, - MATERIAL_PT_transp_game, - MATERIAL_PT_volume_density, - MATERIAL_PT_volume_shading, - MATERIAL_PT_volume_lighting, - MATERIAL_PT_volume_transp, - MATERIAL_PT_volume_integration, - MATERIAL_PT_volume_options, + EEVEE_MATERIAL_PT_context_material, + EEVEE_MATERIAL_PT_surface, + EEVEE_MATERIAL_PT_options, + MATERIAL_PT_viewport, MATERIAL_PT_custom_props, ) + if __name__ == "__main__": # only for live edit. from bpy.utils import register_class for cls in classes: diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py new file mode 100644 index 00000000000..d83639a361c --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py @@ -0,0 +1,321 @@ +# ##### 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> +import bpy +from bpy.types import Menu, Panel, UIList +from rna_prop_ui import PropertyPanel + + +class GPENCIL_MT_color_specials(Menu): + bl_label = "Layer" + + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.color_reveal", icon='RESTRICT_VIEW_OFF', text="Show All") + layout.operator("gpencil.color_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True + + layout.separator() + + layout.operator("gpencil.color_lock_all", icon='LOCKED', text="Lock All") + layout.operator("gpencil.color_unlock_all", icon='UNLOCKED', text="UnLock All") + + layout.separator() + + layout.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="Lock Unselected") + layout.operator("gpencil.lock_layer", icon='COLOR', text="Lock Unused") + + +class GPENCIL_UL_matslots(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + slot = item + ma = slot.material + if (ma is not None) and (ma.grease_pencil is not None): + gpcolor = ma.grease_pencil + + if self.layout_type in {'DEFAULT', 'COMPACT'}: + if gpcolor.lock: + layout.active = False + + row = layout.row(align=True) + row.enabled = not gpcolor.lock + row.prop(ma, "name", text="", emboss=False, icon_value=icon) + + row = layout.row(align=True) + row.prop(gpcolor, "lock", text="", emboss=False) + row.prop(gpcolor, "hide", text="", emboss=False) + if gpcolor.ghost is True: + icon = 'GHOST_DISABLED' + else: + icon = 'GHOST_ENABLED' + row.prop(gpcolor, "ghost", text="", icon=icon, emboss=False) + + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label(text="", icon_value=icon) + + +class GPMaterialButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "material" + + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'GPENCIL' and + ob.active_material and + ob.active_material.grease_pencil) + + +class MATERIAL_PT_gpencil_slots(Panel): + bl_label = "Grease Pencil Material Slots" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "material" + bl_options = {'HIDE_HEADER'} + + @classmethod + def poll(cls, context): + ob = context.object + return ob and ob.type == 'GPENCIL' + + @staticmethod + def draw(self, context): + layout = self.layout + gpd = context.gpencil_data + + mat = context.object.active_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("GPENCIL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows) + + col = row.column(align=True) + col.operator("object.material_slot_add", icon='ZOOMIN', text="") + col.operator("object.material_slot_remove", icon='ZOOMOUT', text="") + + col.menu("GPENCIL_MT_color_specials", 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' + + col.separator() + + sub = col.column(align=True) + sub.operator("gpencil.color_isolate", icon='LOCKED', text="").affect_visibility = False + sub.operator("gpencil.color_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True + + row = layout.row() + + if ob: + row.template_ID(ob, "active_material", new="material.new", live_icon=True) + + if slot: + icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA' + row.prop(slot, "link", icon=icon_link, icon_only=True) + + if gpd.use_stroke_edit_mode: + row = layout.row(align=True) + row.operator("gpencil.stroke_change_color", text="Assign") + row.operator("gpencil.color_select", text="Select") + + elif mat: + row.template_ID(space, "pin_id") + + +# Used as parent for "Stroke" and "Fill" panels +class MATERIAL_PT_gpencil_surface(GPMaterialButtonsPanel, Panel): + bl_label = "Surface" + + @classmethod + def poll(cls, context): + ob = context.object + ma = context.object.active_material + if ma is None or ma.grease_pencil is None: + return False + + return ob and ob.type == 'GPENCIL' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + +class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel): + bl_label = "Stroke" + bl_parent_id = 'MATERIAL_PT_gpencil_surface' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ma = context.object.active_material + if ma is not None and ma.grease_pencil is not None: + gpcolor = ma.grease_pencil + + col = layout.column() + col.active = not gpcolor.lock + + col.prop(gpcolor, "mode") + + col.prop(gpcolor, "stroke_style", text="Style") + + if gpcolor.stroke_style == 'TEXTURE': + row = col.row() + row.enabled = not gpcolor.lock + col = row.column(align=True) + col.template_ID(gpcolor, "stroke_image", open="image.open") + col.prop(gpcolor, "pixel_size", text="UV Factor") + col.prop(gpcolor, "use_stroke_pattern", text="Use As Pattern") + + if gpcolor.stroke_style == 'SOLID' or gpcolor.use_stroke_pattern is True: + col.prop(gpcolor, "color", text="Color") + + +class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel): + bl_label = "Fill" + bl_parent_id = 'MATERIAL_PT_gpencil_surface' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ma = context.object.active_material + if ma is not None and ma.grease_pencil: + gpcolor = ma.grease_pencil + + # color settings + col = layout.column() + col.active = not gpcolor.lock + col.prop(gpcolor, "fill_style", text="Style") + + if gpcolor.fill_style == 'GRADIENT': + col.prop(gpcolor, "gradient_type") + + if gpcolor.fill_style != 'TEXTURE': + col.prop(gpcolor, "fill_color", text="Color") + + if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'): + col.prop(gpcolor, "mix_color", text="Secondary Color") + + if gpcolor.fill_style == 'GRADIENT': + col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True) + + if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'): + col.prop(gpcolor, "flip", text="Flip Colors") + + col.prop(gpcolor, "pattern_shift", text="Location") + col.prop(gpcolor, "pattern_scale", text="Scale") + + if gpcolor.gradient_type == 'RADIAL' and gpcolor.fill_style not in ('SOLID', 'CHESSBOARD'): + col.prop(gpcolor, "pattern_radius", text="Radius") + else: + if gpcolor.fill_style != 'SOLID': + col.prop(gpcolor, "pattern_angle", text="Angle") + + if gpcolor.fill_style == 'CHESSBOARD': + col.prop(gpcolor, "pattern_gridsize", text="Box Size") + + # Texture + if gpcolor.fill_style == 'TEXTURE' or (gpcolor.texture_mix is True and gpcolor.fill_style == 'SOLID'): + col.template_ID(gpcolor, "fill_image", open="image.open") + + if gpcolor.fill_style == 'TEXTURE': + col.prop(gpcolor, "use_fill_pattern", text="Use As Pattern") + if gpcolor.use_fill_pattern is True: + col.prop(gpcolor, "fill_color", text="Color") + + col.prop(gpcolor, "texture_offset", text="Offset") + col.prop(gpcolor, "texture_scale", text="Scale") + col.prop(gpcolor, "texture_angle") + col.prop(gpcolor, "texture_opacity") + col.prop(gpcolor, "texture_clamp", text="Clip Image") + + if gpcolor.use_fill_pattern is False: + col.prop(gpcolor, "texture_mix", text="Mix With Color") + + if gpcolor.texture_mix is True: + col.prop(gpcolor, "fill_color", text="Mix Color") + col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True) + + +class MATERIAL_PT_gpencil_preview(GPMaterialButtonsPanel, Panel): + bl_label = "Preview" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + bl_options = {'DEFAULT_CLOSED'} + + def draw(self, context): + ma = context.object.active_material + self.layout.label(ma.name) + self.layout.template_preview(ma) + + +class MATERIAL_PT_gpencil_custom_props(GPMaterialButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_OPENGL'} + _context_path = "object.active_material" + _property_type = bpy.types.Material + + +class MATERIAL_PT_gpencil_options(GPMaterialButtonsPanel, Panel): + bl_label = "Options" + bl_options = {'DEFAULT_CLOSED'} + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ma = context.object.active_material + if ma is not None and ma.grease_pencil is not None: + gpcolor = ma.grease_pencil + layout.prop(gpcolor, "pass_index") + + +classes = ( + GPENCIL_UL_matslots, + GPENCIL_MT_color_specials, + MATERIAL_PT_gpencil_slots, + MATERIAL_PT_gpencil_preview, + MATERIAL_PT_gpencil_surface, + MATERIAL_PT_gpencil_strokecolor, + MATERIAL_PT_gpencil_fillcolor, + MATERIAL_PT_gpencil_options, + MATERIAL_PT_gpencil_custom_props, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 50cef9124ab..79b2f7b8df8 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -40,7 +40,7 @@ class OBJECT_PT_context_object(ObjectButtonsPanel, Panel): layout.template_ID(space, "pin_id") else: row = layout.row() - row.template_ID(context.scene.objects, "active", filter='AVAILABLE') + row.template_ID(context.view_layer.objects, "active", filter='AVAILABLE') class OBJECT_PT_transform(ObjectButtonsPanel, Panel): @@ -48,150 +48,140 @@ class OBJECT_PT_transform(ObjectButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) ob = context.object - row = layout.row() + col = flow.column() + row = col.row(align=True) + row.prop(ob, "location") + row.use_property_decorate = False + row.prop(ob, "lock_location", text="", emboss=False) - row.column().prop(ob, "location") if ob.rotation_mode == 'QUATERNION': - row.column().prop(ob, "rotation_quaternion", text="Rotation") + col = flow.column() + row = col.row(align=True) + row.prop(ob, "rotation_quaternion", text="Rotation") + sub = row.column(align=True) + sub.use_property_decorate = False + sub.prop(ob, "lock_rotation_w", text="", emboss=False) + sub.prop(ob, "lock_rotation", text="", emboss=False) elif ob.rotation_mode == 'AXIS_ANGLE': # row.column().label(text="Rotation") #row.column().prop(pchan, "rotation_angle", text="Angle") #row.column().prop(pchan, "rotation_axis", text="Axis") - row.column().prop(ob, "rotation_axis_angle", text="Rotation") + col = flow.column() + row = col.row(align=True) + row.prop(ob, "rotation_axis_angle", text="Rotation") + + sub = row.column(align=True) + sub.use_property_decorate = False + sub.prop(ob, "lock_rotation_w", text="", emboss=False) + sub.prop(ob, "lock_rotation", text="", emboss=False) else: - row.column().prop(ob, "rotation_euler", text="Rotation") + col = flow.column() + row = col.row(align=True) + row.prop(ob, "rotation_euler", text="Rotation") + row.use_property_decorate = False + row.prop(ob, "lock_rotation", text="", emboss=False) + + col = flow.column() + row = col.row(align=True) + row.prop(ob, "scale") + row.use_property_decorate = False + row.prop(ob, "lock_scale", text="", emboss=False) - row.column().prop(ob, "scale") - - layout.prop(ob, "rotation_mode") + row = layout.row(align=True) + row.prop(ob, "rotation_mode") + row.label(text="", icon='BLANK1') class OBJECT_PT_delta_transform(ObjectButtonsPanel, Panel): bl_label = "Delta Transform" + bl_parent_id = "OBJECT_PT_transform" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=True, align=False) ob = context.object - row = layout.row() + col = flow.column() + col.prop(ob, "delta_location") - row.column().prop(ob, "delta_location") + col = flow.column() if ob.rotation_mode == 'QUATERNION': - row.column().prop(ob, "delta_rotation_quaternion", text="Rotation") + col.prop(ob, "delta_rotation_quaternion", text="Rotation") elif ob.rotation_mode == 'AXIS_ANGLE': # row.column().label(text="Rotation") #row.column().prop(pchan, "delta_rotation_angle", text="Angle") #row.column().prop(pchan, "delta_rotation_axis", text="Axis") #row.column().prop(ob, "delta_rotation_axis_angle", text="Rotation") - row.column().label(text="Not for Axis-Angle") + col.label(text="Not for Axis-Angle") else: - row.column().prop(ob, "delta_rotation_euler", text="Delta Rotation") - - row.column().prop(ob, "delta_scale") - - -class OBJECT_PT_transform_locks(ObjectButtonsPanel, Panel): - bl_label = "Transform Locks" - bl_options = {'DEFAULT_CLOSED'} - - def draw(self, context): - layout = self.layout - - ob = context.object - - split = layout.split(percentage=0.1) + col.prop(ob, "delta_rotation_euler", text="Delta Rotation") - col = split.column(align=True) - col.label(text="") - col.label(text="X:") - col.label(text="Y:") - col.label(text="Z:") - - split.column().prop(ob, "lock_location", text="Location") - split.column().prop(ob, "lock_rotation", text="Rotation") - split.column().prop(ob, "lock_scale", text="Scale") - - if ob.rotation_mode in {'QUATERNION', 'AXIS_ANGLE'}: - row = layout.row() - row.prop(ob, "lock_rotations_4d", text="Lock Rotation") - - sub = row.row() - sub.active = ob.lock_rotations_4d - sub.prop(ob, "lock_rotation_w", text="W") + col = flow.column() + col.prop(ob, "delta_scale") class OBJECT_PT_relations(ObjectButtonsPanel, Panel): bl_label = "Relations" + bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) ob = context.object - split = layout.split() - - col = split.column() - col.prop(ob, "layers") - col.separator() - col.prop(ob, "pass_index") - - col = split.column() - col.label(text="Parent:") - col.prop(ob, "parent", text="") - - sub = col.column() - sub.prop(ob, "parent_type", text="") + col = flow.column() + col.prop(ob, "parent") + sub = col.row(align=True) + sub.prop(ob, "parent_type") parent = ob.parent if parent and ob.parent_type == 'BONE' and parent.type == 'ARMATURE': - sub.prop_search(ob, "parent_bone", parent.data, "bones", text="") + sub.prop_search(ob, "parent_bone", parent.data, "bones") sub.active = (parent is not None) + col = flow.column() + col.active = (ob.parent is not None) + col.prop(ob, "use_slow_parent") + sub = col.row(align=True) + sub.active = (ob.use_slow_parent) + sub.prop(ob, "slow_parent_offset", text="Offset") -class OBJECT_PT_relations_extras(ObjectButtonsPanel, Panel): - bl_label = "Relations Extras" - bl_options = {'DEFAULT_CLOSED'} - - def draw(self, context): - layout = self.layout - - ob = context.object - - split = layout.split() + col = flow.column() + col.separator() - if context.scene.render.engine != 'BLENDER_GAME': - col = split.column() - col.label(text="Tracking Axes:") - col.prop(ob, "track_axis", text="Axis") - col.prop(ob, "up_axis", text="Up Axis") + col.prop(ob, "track_axis", text="Tracking Axis") + col.prop(ob, "up_axis", text="Up Axis") - col = split.column() - col.prop(ob, "use_slow_parent") - row = col.row() - row.active = ((ob.parent is not None) and (ob.use_slow_parent)) - row.prop(ob, "slow_parent_offset", text="Offset") + col = flow.column() + col.separator() - layout.prop(ob, "use_extra_recalc_object") - layout.prop(ob, "use_extra_recalc_data") + col.prop(ob, "pass_index") -class GROUP_MT_specials(Menu): - bl_label = "Group Specials" +class COLLECTION_MT_specials(Menu): + bl_label = "Collection Specials" def draw(self, context): layout = self.layout - layout.operator("object.group_unlink", icon='X') - layout.operator("object.grouped_select") + layout.operator("object.collection_unlink", icon='X') + layout.operator("object.collection_objects_select") layout.operator("object.dupli_offset_from_cursor") -class OBJECT_PT_groups(ObjectButtonsPanel, Panel): - bl_label = "Groups" +class OBJECT_PT_collections(ObjectButtonsPanel, Panel): + bl_label = "Collections" + bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout @@ -199,42 +189,40 @@ class OBJECT_PT_groups(ObjectButtonsPanel, Panel): obj = context.object row = layout.row(align=True) - if bpy.data.groups: - row.operator("object.group_link", text="Add to Group") + if bpy.data.collections: + row.operator("object.collection_link", text="Add to Collection") else: - row.operator("object.group_add", text="Add to Group") - row.operator("object.group_add", text="", icon='ZOOMIN') + row.operator("object.collection_add", text="Add to Collection") + row.operator("object.collection_add", text="", icon='ZOOMIN') obj_name = obj.name - for group in bpy.data.groups: + for collection in bpy.data.collections: # XXX this is slow and stupid!, we need 2 checks, one thats fast # and another that we can be sure its not a name collision # from linked library data - group_objects = group.objects - if obj_name in group.objects and obj in group_objects[:]: + collection_objects = collection.objects + if obj_name in collection.objects and obj in collection_objects[:]: col = layout.column(align=True) - col.context_pointer_set("group", group) + col.context_pointer_set("collection", collection) row = col.box().row() - row.prop(group, "name", text="") - row.operator("object.group_remove", text="", icon='X', emboss=False) - row.menu("GROUP_MT_specials", icon='DOWNARROW_HLT', text="") - - split = col.box().split() + row.prop(collection, "name", text="") + row.operator("object.collection_remove", text="", icon='X', emboss=False) + row.menu("COLLECTION_MT_specials", icon='DOWNARROW_HLT', text="") - col = split.column() - col.prop(group, "layers", text="Dupli Visibility") - - col = split.column() - col.prop(group, "dupli_offset", text="") + row = col.box().row() + row.prop(collection, "dupli_offset", text="") class OBJECT_PT_display(ObjectButtonsPanel, Panel): - bl_label = "Display" + bl_label = "Viewport Display" + bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) obj = context.object obj_type = obj.type @@ -243,84 +231,93 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel): is_empty_image = (obj_type == 'EMPTY' and obj.empty_draw_type == 'IMAGE') is_dupli = (obj.dupli_type != 'NONE') - split = layout.split() - - col = split.column() + col = flow.column(align=True) col.prop(obj, "show_name", text="Name") col.prop(obj, "show_axis", text="Axis") + # Makes no sense for cameras, armatures, etc.! # but these settings do apply to dupli instances + col = flow.column(align=True) if is_geometry or is_dupli: - col.prop(obj, "show_wire", text="Wire") + col.prop(obj, "show_wire", text="Wireframe") if obj_type == 'MESH' or is_dupli: col.prop(obj, "show_all_edges") - col = split.column() - row = col.row() - row.prop(obj, "show_bounds", text="Bounds") - sub = row.row() + col = flow.column() + col.prop(obj, "show_bounds", text="Bounds") + sub = col.column() sub.active = obj.show_bounds - sub.prop(obj, "draw_bounds_type", text="") + sub.prop(obj, "draw_bounds_type") + col = flow.column() if is_geometry: col.prop(obj, "show_texture_space", text="Texture Space") - col.prop(obj, "show_x_ray", text="X-Ray") - if obj_type == 'MESH' or is_empty_image: - col.prop(obj, "show_transparent", text="Transparency") + col.prop(obj.display, "show_shadows", text="Shadow") - split = layout.split() + col.prop(obj, "show_x_ray", text="X-Ray") + # if obj_type == 'MESH' or is_empty_image: + # col.prop(obj, "show_transparent", text="Transparency") - col = split.column() + col = flow.column() if is_wire: # wire objects only use the max. draw type for duplis col.active = is_dupli - col.label(text="Maximum Dupli Draw Type:") - else: - col.label(text="Maximum Draw Type:") - col.prop(obj, "draw_type", text="") + col.prop( + obj, "draw_type", + text="Maximum Draw Type" if is_wire else "Maximum Draw Type", + ) - col = split.column() if is_geometry or is_empty_image: # Only useful with object having faces/materials... - col.label(text="Object Color:") - col.prop(obj, "color", text="") + col.prop(obj, "color") class OBJECT_PT_duplication(ObjectButtonsPanel, Panel): bl_label = "Duplication" + bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout ob = context.object - layout.row().prop(ob, "dupli_type", expand=True) + row = layout.row() + row.prop(ob, "dupli_type", expand=True) + + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) if ob.dupli_type == 'FRAMES': - split = layout.split() - col = split.column(align=True) + col = flow.column(align=True) col.prop(ob, "dupli_frames_start", text="Start") col.prop(ob, "dupli_frames_end", text="End") - col = split.column(align=True) + col = flow.column(align=True) col.prop(ob, "dupli_frames_on", text="On") col.prop(ob, "dupli_frames_off", text="Off") - layout.prop(ob, "use_dupli_frames_speed", text="Speed") + col = flow.column(align=True) + col.prop(ob, "use_dupli_frames_speed", text="Speed") elif ob.dupli_type == 'VERTS': layout.prop(ob, "use_dupli_vertices_rotation", text="Rotation") elif ob.dupli_type == 'FACES': - row = layout.row() - row.prop(ob, "use_dupli_faces_scale", text="Scale") - sub = row.row() + col = flow.column() + col.prop(ob, "use_dupli_faces_scale", text="Scale") + sub = col.column() sub.active = ob.use_dupli_faces_scale sub.prop(ob, "dupli_faces_scale", text="Inherit Scale") - elif ob.dupli_type == 'GROUP': - layout.prop(ob, "dupli_group", text="Group") + elif ob.dupli_type == 'COLLECTION': + col = flow.column() + col.prop(ob, "dupli_group", text="Collection") + + if ob.dupli_type != 'NONE' or len(ob.particle_systems): + col = flow.column(align=True) + col.prop(ob, "show_duplicator_for_viewport") + col.prop(ob, "show_duplicator_for_render") from .properties_animviz import ( @@ -332,6 +329,7 @@ from .properties_animviz import ( class OBJECT_PT_motion_paths(MotionPathButtonsPanel, Panel): #bl_label = "Object Motion Paths" bl_context = "object" + bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): @@ -362,7 +360,7 @@ class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel): # , Panel): # inherit fr class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "object" _property_type = bpy.types.Object @@ -371,13 +369,11 @@ classes = ( OBJECT_PT_context_object, OBJECT_PT_transform, OBJECT_PT_delta_transform, - OBJECT_PT_transform_locks, OBJECT_PT_relations, - OBJECT_PT_relations_extras, - GROUP_MT_specials, - OBJECT_PT_groups, - OBJECT_PT_display, + COLLECTION_MT_specials, + OBJECT_PT_collections, OBJECT_PT_duplication, + OBJECT_PT_display, OBJECT_PT_motion_paths, OBJECT_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index b4049bf7b68..f1e5102f061 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -96,8 +96,8 @@ class VIEW3D_MT_tools_projectpaint_clone(Menu): def draw(self, context): layout = self.layout - for i, tex in enumerate(context.active_object.data.uv_textures): - props = layout.operator("wm.context_set_int", text=tex.name, translate=False) + for i, uv_layer in enumerate(context.active_object.data.uv_layers): + props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False) props.data_path = "active_object.data.uv_texture_clone_index" props.value = i diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 14ca6f700f4..393c9784be8 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -21,6 +21,7 @@ import bpy from bpy.types import Panel, Menu from rna_prop_ui import PropertyPanel from bpy.app.translations import pgettext_iface as iface_ +from bl_operators.presets import PresetMenu from .properties_physics_common import ( point_cache_ui, @@ -42,7 +43,7 @@ def particle_panel_enabled(context, psys): def particle_panel_poll(cls, context): psys = context.particle_system - engine = context.scene.render.engine + engine = context.engine settings = 0 if psys: @@ -66,7 +67,7 @@ def particle_get_settings(context): class PARTICLE_MT_specials(Menu): bl_label = "Particle Specials" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -82,12 +83,12 @@ class PARTICLE_MT_specials(Menu): layout.operator("particle.duplicate_particle_system") -class PARTICLE_MT_hair_dynamics_presets(Menu): +class PARTICLE_PT_hair_dynamics_presets(PresetMenu): bl_label = "Hair Dynamics Presets" preset_subdir = "hair_dynamics" preset_operator = "script.execute_preset" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - draw = Menu.draw_preset + preset_add_operator = "particle.hair_dynamics_preset_add" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} class ParticleButtonsPanel: @@ -131,20 +132,16 @@ class PARTICLE_UL_particle_systems(bpy.types.UIList): class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - engine = context.scene.render.engine + engine = context.engine return (context.particle_system or context.object or context.space_data.pin_id) and (engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout - if context.scene.render.engine == 'BLENDER_GAME': - layout.label("Not available in the Game Engine") - return - ob = context.object psys = context.particle_system part = 0 @@ -153,7 +150,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): row = layout.row() row.template_list("PARTICLE_UL_particle_systems", "particle_systems", ob, "particle_systems", - ob.particle_systems, "active_index", rows=1) + ob.particle_systems, "active_index", rows=2) col = row.column(align=True) col.operator("object.particle_system_add", icon='ZOOMIN', text="") @@ -238,7 +235,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): class PARTICLE_PT_emission(ParticleButtonsPanel, Panel): bl_label = "Emission" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -259,67 +256,81 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, Panel): psys = context.particle_system part = particle_get_settings(context) + layout.use_property_split = True + layout.enabled = particle_panel_enabled(context, psys) and (psys is None or not psys.has_multiple_caches) - row = layout.row() - row.active = part.emit_from == 'VERT' or part.distribution != 'GRID' - row.prop(part, "count") + col = layout.column() + col.active = part.emit_from == 'VERT' or part.distribution != 'GRID' + col.prop(part, "count") if part.type == 'HAIR': - row.prop(part, "hair_length") + col.prop(part, "hair_length") if not part.use_advanced_hair: row = layout.row() - row.prop(part, "use_modifier_stack") + col.prop(part, "use_modifier_stack") return if part.type != 'HAIR': - split = layout.split() - col = split.column(align=True) - col.prop(part, "frame_start") - col.prop(part, "frame_end") + col = layout.column() + + sub = col.column(align=True) + sub.prop(part, "frame_start", text="Frame Start") + sub.prop(part, "frame_end", text="End") - col = split.column(align=True) col.prop(part, "lifetime") - col.prop(part, "lifetime_random", slider=True) + col.prop(part, "lifetime_random", slider=True, text="Lifetime Randomness") - layout.label(text="Emit From:") - layout.row().prop(part, "emit_from", expand=True) - row = layout.row() +class PARTICLE_PT_emission_source(ParticleButtonsPanel, Panel): + bl_label = "Source" + bl_parent_id = "PARTICLE_PT_emission" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + + part = particle_get_settings(context) + + layout.use_property_split = True + + col = layout.column() + col.prop(part, "emit_from") + col.prop(part, "use_modifier_stack") + if part.emit_from == 'FACE' or part.emit_from == 'VOLUME': + col.prop(part, "distribution") + if part.emit_from == 'VERT': - row.prop(part, "use_emit_random") + col.prop(part, "use_emit_random", text="Random Order") elif part.distribution == 'GRID': - row.prop(part, "invert_grid") - row.prop(part, "hexagonal_grid") + col.label(text="Grid") + col.prop(part, "invert_grid") + col.prop(part, "hexagonal_grid") else: - row.prop(part, "use_emit_random") - row.prop(part, "use_even_distribution") + col.prop(part, "use_emit_random") + col.prop(part, "use_even_distribution") if part.emit_from == 'FACE' or part.emit_from == 'VOLUME': - layout.row().prop(part, "distribution", expand=True) - row = layout.row() if part.distribution == 'JIT': - row.prop(part, "userjit", text="Particles/Face") - row.prop(part, "jitter_factor", text="Jittering Amount", slider=True) + col.prop(part, "userjit", text="Particles/Face") + col.prop(part, "jitter_factor", text="Jittering Amount", slider=True) elif part.distribution == 'GRID': - row.prop(part, "grid_resolution") - row.prop(part, "grid_random", text="Random", slider=True) - - row = layout.row() - row.prop(part, "use_modifier_stack") + col.prop(part, "grid_resolution") + col.prop(part, "grid_random", text="Random", slider=True) class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel): bl_label = "Hair Dynamics" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): psys = context.particle_system - engine = context.scene.render.engine + engine = context.engine if psys is None: return False if psys.settings is None: @@ -330,12 +341,23 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel): psys = context.particle_system self.layout.prop(psys, "use_hair_dynamics", text="") + def draw_header_preset(self, context): + psys = context.particle_system + + if not psys.cloth: + return + + layout = self.layout + layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False + PARTICLE_PT_hair_dynamics_presets.draw_panel_header(layout) + def draw(self, context): layout = self.layout psys = context.particle_system if not psys.cloth: + layout.label(text="Hair dynamics disabled") return cloth_md = psys.cloth @@ -344,49 +366,20 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel): layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False - row = layout.row(align=True) - row.menu("PARTICLE_MT_hair_dynamics_presets", text=bpy.types.PARTICLE_MT_hair_dynamics_presets.bl_label) - row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMIN') - row.operator("particle.hair_dynamics_preset_add", text="", icon='ZOOMOUT').remove_active = True - - split = layout.column() - - col = split.column() - col.label(text="Structure") - col.prop(cloth, "mass") - sub = col.column(align=True) - subsub = sub.row(align=True) - subsub.prop(cloth, "bending_stiffness", text="Stiffness") - subsub.prop(psys.settings, "bending_random", text="Random") - sub.prop(cloth, "bending_damping", text="Damping") - # XXX has no noticeable effect with stiff hair structure springs - #col.prop(cloth, "spring_damping", text="Damping") - - split.separator() - - col = split.column() - col.label(text="Volume") - col.prop(cloth, "air_damping", text="Air Drag") - col.prop(cloth, "internal_friction", slider=True) - sub = col.column(align=True) - sub.prop(cloth, "density_target", text="Density Target") - sub.prop(cloth, "density_strength", slider=True, text="Strength") - col.prop(cloth, "voxel_cell_size") + layout.use_property_split = True - split.separator() + layout.separator() - col = split.column() - col.label(text="Pinning") - col.prop(cloth, "pin_stiffness", text="Goal Strength") + col = layout.column() + col.prop(cloth, "quality", text="Quality Steps", slider=True) + col.prop(psys.settings, "show_hair_grid", text="Display Hair Grid") - split.separator() + layout.separator() - col = split.column() - col.label(text="Quality:") - col.prop(cloth, "quality", text="Steps", slider=True) + col = layout.column() + col.prop(cloth, "pin_stiffness", text="Pin Goal Strength") - row = col.row() - row.prop(psys.settings, "show_hair_grid", text="HairGrid") + layout.separator() if result: box = layout.box() @@ -409,15 +402,80 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, Panel): box.label("Error: %.5f .. %.5f (avg. %.5f)" % (result.min_error, result.max_error, result.avg_error)) +class PARTICLE_PT_hair_dynamics_structure(ParticleButtonsPanel, Panel): + bl_label = "Structure" + bl_parent_id = "PARTICLE_PT_hair_dynamics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + return context.particle_system.cloth is not None + + def draw(self, context): + layout = self.layout + + psys = context.particle_system + cloth_md = psys.cloth + cloth = cloth_md.settings + result = cloth_md.solver_result + + layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False + + layout.use_property_split = True + + col = layout.column() + col.prop(cloth, "mass") + sub = col.column(align=True) + sub.prop(cloth, "bending_stiffness", text="Stiffness") + sub.prop(psys.settings, "bending_random", text="Random") + col.prop(cloth, "bending_damping", text="Damping") + # XXX has no noticeable effect with stiff hair structure springs + #col.prop(cloth, "spring_damping", text="Damping") + + +class PARTICLE_PT_hair_dynamics_volume(ParticleButtonsPanel, Panel): + bl_label = "Volume" + bl_parent_id = "PARTICLE_PT_hair_dynamics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + return context.particle_system.cloth is not None + + def draw(self, context): + layout = self.layout + + psys = context.particle_system + cloth_md = psys.cloth + cloth = cloth_md.settings + result = cloth_md.solver_result + + layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked is False + + layout.use_property_split = True + + col = layout.column() + col.prop(cloth, "air_damping", text="Air Drag") + col.prop(cloth, "internal_friction", slider=True) + col.prop(cloth, "voxel_cell_size") + + col.separator() + + col.prop(cloth, "density_target", text="Density Target") + col.prop(cloth, "density_strength", slider=True, text="Density Strength") + + class PARTICLE_PT_cache(ParticleButtonsPanel, Panel): bl_label = "Cache" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): psys = context.particle_system - engine = context.scene.render.engine + engine = context.engine if psys is None: return False if psys.settings is None: @@ -442,7 +500,8 @@ class PARTICLE_PT_cache(ParticleButtonsPanel, Panel): class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel): bl_label = "Velocity" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -463,37 +522,35 @@ class PARTICLE_PT_velocity(ParticleButtonsPanel, Panel): part = particle_get_settings(context) layout.enabled = particle_panel_enabled(context, psys) + layout.use_property_split = True - split = layout.split() - - col = split.column() - col.label(text="Emitter Geometry:") + col = layout.column() col.prop(part, "normal_factor") sub = col.column(align=True) - sub.prop(part, "tangent_factor") - sub.prop(part, "tangent_phase", slider=True) + sub.prop(part, "tangent_factor", text="Tangent") + sub.prop(part, "tangent_phase", slider=True, text="Tangent Phase") - col = split.column() - col.label(text="Emitter Object:") - col.prop(part, "object_align_factor", text="") + col.separator() + + col.prop(part, "object_align_factor") + + col.separator() - layout.label(text="Other:") - row = layout.row() if part.emit_from == 'PARTICLE': - row.prop(part, "particle_factor") + col.prop(part, "particle_factor") else: - row.prop(part, "object_factor", slider=True) - row.prop(part, "factor_random") + col.prop(part, "object_factor", slider=True) + col.prop(part, "factor_random", text="Randomize") # if part.type=='REACTOR': - # sub.prop(part, "reactor_factor") - # sub.prop(part, "reaction_shape", slider=True) + # sub.prop(part, "reactor_factor") + # sub.prop(part, "reaction_shape", slider=True) class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel): bl_label = "Rotation" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -526,37 +583,52 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, Panel): part = context.space_data.pin_id layout.enabled = particle_panel_enabled(context, psys) and part.use_rotations + layout.use_property_split = True - layout.label(text="Initial Orientation:") + col = layout.column() - split = layout.split() + col.prop(part, "rotation_mode") + col.prop(part, "rotation_factor_random", slider=True, text="Randomize") - col = split.column(align=True) - col.prop(part, "rotation_mode", text="") - col.prop(part, "rotation_factor_random", slider=True, text="Random") + col.separator() - col = split.column(align=True) col.prop(part, "phase_factor", slider=True) - col.prop(part, "phase_factor_random", text="Random", slider=True) + col.prop(part, "phase_factor_random", text="Randomize Phase ", slider=True) if part.type != 'HAIR': - layout.label(text="Angular Velocity:") + col.prop(part, "use_dynamic_rotation") - split = layout.split() - col = split.column(align=True) - col.prop(part, "angular_velocity_mode", text="") - sub = col.column(align=True) - sub.active = part.angular_velocity_mode != 'NONE' - sub.prop(part, "angular_velocity_factor", text="") +class PARTICLE_PT_rotation_angular_velocity(ParticleButtonsPanel, Panel): + bl_label = "Angular Velocity" + bl_parent_id = "PARTICLE_PT_rotation" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - col = split.column() - col.prop(part, "use_dynamic_rotation") + def draw(self, context): + layout = self.layout + + psys = context.particle_system + if psys: + part = psys.settings + else: + part = context.space_data.pin_id + + layout.enabled = particle_panel_enabled(context, psys) and part.use_rotations + layout.use_property_split = True + + col = layout.column() + + col.prop(part, "angular_velocity_mode", text="Axis") + sub = col.column(align=True) + sub.active = part.angular_velocity_mode != 'NONE' + sub.prop(part, "angular_velocity_factor", text="Amount") class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): bl_label = "Physics" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -572,233 +644,455 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True psys = context.particle_system part = particle_get_settings(context) layout.enabled = particle_panel_enabled(context, psys) - layout.row().prop(part, "physics_type", expand=True) + layout.prop(part, "physics_type") - row = layout.row() + col = layout.column() if part.physics_type != 'NO': - col = row.column(align=True) + col = col.column() col.prop(part, "mass") col.prop(part, "use_multiply_size_mass", text="Multiply mass with size") - if part.physics_type in {'NEWTON', 'FLUID'}: - split = layout.split() - - col = split.column() - col.label(text="Forces:") - col.prop(part, "brownian_factor") - col.prop(part, "drag_factor", slider=True) - col.prop(part, "damping", slider=True) - - col = split.column() - col.label(text="Integration:") - col.prop(part, "integrator", text="") - col.prop(part, "timestep") - sub = col.row() - sub.prop(part, "subframes") - supports_courant = part.physics_type == 'FLUID' - subsub = sub.row() - subsub.enabled = supports_courant - subsub.prop(part, "use_adaptive_subframes", text="") - if supports_courant and part.use_adaptive_subframes: - col.prop(part, "courant_target", text="Threshold") + if part.physics_type == 'FLUID': + fluid = part.fluid - row = layout.row() - row.prop(part, "use_size_deflect") - row.prop(part, "use_die_on_collision") - - layout.prop(part, "collision_group") - - if part.physics_type == 'FLUID': - fluid = part.fluid - - split = layout.split() - sub = split.row() - sub.prop(fluid, "solver", expand=True) - - split = layout.split() - - col = split.column() - col.label(text="Fluid Properties:") - col.prop(fluid, "stiffness", text="Stiffness") - col.prop(fluid, "linear_viscosity", text="Viscosity") - col.prop(fluid, "buoyancy", text="Buoyancy", slider=True) - - col = split.column() - col.label(text="Advanced:") - - if fluid.solver == 'DDR': - sub = col.row() - sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion) - sub.prop(fluid, "factor_repulsion", text="") - - sub = col.row() - sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity) - sub.prop(fluid, "factor_stiff_viscosity", text="") - - sub = col.row() - sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius) - sub.prop(fluid, "factor_radius", text="") - - sub = col.row() - sub.prop(fluid, "rest_density", slider=fluid.use_factor_density) - sub.prop(fluid, "use_factor_density", text="") - - if fluid.solver == 'CLASSICAL': - # With the classical solver, it is possible to calculate the - # spacing between particles when the fluid is at rest. This - # makes it easier to set stable initial conditions. - particle_volume = part.mass / fluid.rest_density - spacing = pow(particle_volume, 1.0 / 3.0) - sub = col.row() - sub.label(text="Spacing: %g" % spacing) - - elif fluid.solver == 'DDR': - split = layout.split() - - col = split.column() - col.label(text="Springs:") - col.prop(fluid, "spring_force", text="Force") - col.prop(fluid, "use_viscoelastic_springs") - sub = col.column(align=True) - sub.active = fluid.use_viscoelastic_springs - sub.prop(fluid, "yield_ratio", slider=True) - sub.prop(fluid, "plasticity", slider=True) - - col = split.column() - col.label(text="Advanced:") - sub = col.row() - sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length) - sub.prop(fluid, "factor_rest_length", text="") - col.label(text="") - sub = col.column() - sub.active = fluid.use_viscoelastic_springs - sub.prop(fluid, "use_initial_rest_length") - sub.prop(fluid, "spring_frames", text="Frames") + col.separator() + col.prop(fluid, "solver") + col.prop(fluid, "stiffness", text="Stiffness") + col.prop(fluid, "linear_viscosity", text="Viscosity") + col.prop(fluid, "buoyancy", text="Buoyancy", slider=True) elif part.physics_type == 'KEYED': - split = layout.split() - sub = split.column() - row = layout.row() - col = row.column() - col.active = not psys.use_keyed_timing - col.prop(part, "keyed_loops", text="Loops") + sub = col.column() + sub.active = not psys.use_keyed_timing + sub.prop(part, "keyed_loops", text="Loops") if psys: - row.prop(psys, "use_keyed_timing", text="Use Timing") + col.prop(psys, "use_keyed_timing", text="Use Timing") - layout.label(text="Keys:") - elif part.physics_type == 'BOIDS': - boids = part.boids + col.label(text="Keys") - row = layout.row() - row.prop(boids, "use_flight") - row.prop(boids, "use_land") - row.prop(boids, "use_climb") - - split = layout.split() - - col = split.column(align=True) - col.active = boids.use_flight - col.prop(boids, "air_speed_max") - col.prop(boids, "air_speed_min", slider=True) - col.prop(boids, "air_acc_max", slider=True) - col.prop(boids, "air_ave_max", slider=True) - col.prop(boids, "air_personal_space") - row = col.row(align=True) - row.active = (boids.use_land or boids.use_climb) and boids.use_flight - row.prop(boids, "land_smooth") - - col = split.column(align=True) - col.active = boids.use_land or boids.use_climb - col.prop(boids, "land_speed_max") - col.prop(boids, "land_jump_speed") - col.prop(boids, "land_acc_max", slider=True) - col.prop(boids, "land_ave_max", slider=True) - col.prop(boids, "land_personal_space") - col.prop(boids, "land_stick_force") - - layout.prop(part, "collision_group") - - split = layout.split() - - col = split.column(align=True) - col.label(text="Battle:") - col.prop(boids, "health") - col.prop(boids, "strength") - col.prop(boids, "aggression") - col.prop(boids, "accuracy") - col.prop(boids, "range") - col = split.column() - col.label(text="Misc:") - col.prop(boids, "bank", slider=True) - col.prop(boids, "pitch", slider=True) - col.prop(boids, "height", slider=True) - - if psys and part.physics_type in {'KEYED', 'BOIDS', 'FLUID'}: - if part.physics_type == 'BOIDS': - layout.label(text="Relations:") +class PARTICLE_PT_physics_fluid_advanced(ParticleButtonsPanel, Panel): + bl_label = "Advanced" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID': + return True + else: + return False + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + col = layout.column() + + if fluid.solver == 'DDR': + sub = col.column() + sub.prop(fluid, "repulsion", slider=fluid.factor_repulsion) + sub.prop(fluid, "factor_repulsion") + + sub.prop(fluid, "stiff_viscosity", slider=fluid.factor_stiff_viscosity) + sub.prop(fluid, "factor_stiff_viscosity") + + sub = col.column() + sub.prop(fluid, "fluid_radius", slider=fluid.factor_radius) + sub.prop(fluid, "factor_radius") + + sub.prop(fluid, "rest_density", slider=fluid.use_factor_density) + sub.prop(fluid, "use_factor_density") + + if fluid.solver == 'CLASSICAL': + # With the classical solver, it is possible to calculate the + # spacing between particles when the fluid is at rest. This + # makes it easier to set stable initial conditions. + particle_volume = part.mass / fluid.rest_density + spacing = pow(particle_volume, 1.0 / 3.0) + + sub.label(text="Spacing: %g" % spacing) + + +class PARTICLE_PT_physics_fluid_springs(ParticleButtonsPanel, Panel): + bl_label = "Springs" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID' and fluid.solver == 'DDR': + return True + else: + return False + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + col = layout.column() + + col.prop(fluid, "spring_force", text="Force") + + +class PARTICLE_PT_physics_fluid_springs_viscoelastic(ParticleButtonsPanel, Panel): + bl_label = "Viscoelastic Springs" + bl_parent_id = "PARTICLE_PT_physics_fluid_springs" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID' and fluid.solver == 'DDR': + return True + else: + return False + + def draw_header(self, context): + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + self.layout.prop(fluid, "use_viscoelastic_springs", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + col = layout.column() + col.active = fluid.use_viscoelastic_springs + col.prop(fluid, "yield_ratio", slider=True) + col.prop(fluid, "plasticity", slider=True) + + col.separator() + + col.prop(fluid, "use_initial_rest_length") + col.prop(fluid, "spring_frames", text="Frames") + + +class PARTICLE_PT_physics_fluid_springs_advanced(ParticleButtonsPanel, Panel): + bl_label = "Advanced" + bl_parent_id = "PARTICLE_PT_physics_fluid_springs" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + fluid = part.fluid + if part.physics_type == 'FLUID' and fluid.solver == 'DDR': + return True + else: + return False + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + fluid = part.fluid + + sub = layout.column() + sub.prop(fluid, "rest_length", slider=fluid.factor_rest_length) + sub.prop(fluid, "factor_rest_length") + + +class PARTICLE_PT_physics_boids_movement(ParticleButtonsPanel, Panel): + bl_label = "Movement" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'BOIDS'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + boids = part.boids + + col = layout.column() + + col.prop(boids, "use_flight") + col.prop(boids, "use_land") + col.prop(boids, "use_climb") + + col = layout.column() + + col.active = boids.use_flight + sub = col.column() + sub.prop(boids, "air_speed_max") + sub.prop(boids, "air_speed_min", slider=True) + col.prop(boids, "air_acc_max", slider=True) + col.prop(boids, "air_ave_max", slider=True) + col.prop(boids, "air_personal_space") + row = col.row(align=True) + row.active = (boids.use_land or boids.use_climb) and boids.use_flight + row.prop(boids, "land_smooth") + + layout.separator() + + col = layout.column() + col.active = boids.use_land or boids.use_climb + col.prop(boids, "land_speed_max") + col.prop(boids, "land_jump_speed") + col.prop(boids, "land_acc_max", slider=True) + col.prop(boids, "land_ave_max", slider=True) + col.prop(boids, "land_personal_space") + col.prop(boids, "land_stick_force") + + layout.separator() + + layout.prop(part, "collision_group") + + +class PARTICLE_PT_physics_boids_battle(ParticleButtonsPanel, Panel): + bl_label = "Battle" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'BOIDS'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + boids = part.boids + + col = layout.column() + + col.prop(boids, "health") + col.prop(boids, "strength") + col.prop(boids, "aggression") + col.prop(boids, "accuracy") + col.prop(boids, "range") + + +class PARTICLE_PT_physics_boids_misc(ParticleButtonsPanel, Panel): + bl_label = "Misc" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'BOIDS'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + boids = part.boids + + col = layout.column() + + col.prop(boids, "bank", slider=True) + col.prop(boids, "pitch", slider=True) + col.prop(boids, "height", slider=True) + + +class PARTICLE_PT_physics_relations(ParticleButtonsPanel, Panel): + bl_label = "Relations" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'KEYED', 'BOIDS', 'FLUID'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + + row = layout.row() + row.template_list("UI_UL_list", "particle_targets", psys, "targets", + psys, "active_particle_target_index", rows=4) + + col = row.column() + sub = col.row() + subsub = sub.column(align=True) + subsub.operator("particle.new_target", icon='ZOOMIN', text="") + subsub.operator("particle.target_remove", icon='ZOOMOUT', text="") + sub = col.row() + subsub = sub.column(align=True) + subsub.operator("particle.target_move_up", icon='TRIA_UP', text="") + subsub.operator("particle.target_move_down", icon='TRIA_DOWN', text="") + + key = psys.active_particle_target + + if key: + if part.physics_type == 'KEYED': + col = layout.column() + # doesn't work yet + #col.alert = key.valid + col.prop(key, "object") + col.prop(key, "system", text="System") + + col.active = psys.use_keyed_timing + col.prop(key, "time") + col.prop(key, "duration") + elif part.physics_type == 'BOIDS': + sub = layout.column() + # doesn't work yet + #sub.alert = key.valid + sub.prop(key, "object") + sub.prop(key, "system", text="System") + layout.prop(key, "alliance") elif part.physics_type == 'FLUID': - layout.label(text="Fluid Interaction:") + sub = layout.column() + # doesn't work yet + #sub.alert = key.valid + sub.prop(key, "object") + sub.prop(key, "system", text="System") - row = layout.row() - row.template_list("UI_UL_list", "particle_targets", psys, "targets", - psys, "active_particle_target_index", rows=4) - - col = row.column() - sub = col.row() - subsub = sub.column(align=True) - subsub.operator("particle.new_target", icon='ZOOMIN', text="") - subsub.operator("particle.target_remove", icon='ZOOMOUT', text="") - sub = col.row() - subsub = sub.column(align=True) - subsub.operator("particle.target_move_up", icon='TRIA_UP', text="") - subsub.operator("particle.target_move_down", icon='TRIA_DOWN', text="") - - key = psys.active_particle_target - if key: - row = layout.row() - if part.physics_type == 'KEYED': - col = row.column() - # doesn't work yet - #col.alert = key.valid - col.prop(key, "object", text="") - col.prop(key, "system", text="System") - col = row.column() - col.active = psys.use_keyed_timing - col.prop(key, "time") - col.prop(key, "duration") - elif part.physics_type == 'BOIDS': - sub = row.row() - # doesn't work yet - #sub.alert = key.valid - sub.prop(key, "object", text="") - sub.prop(key, "system", text="System") - - layout.row().prop(key, "alliance", expand=True) - elif part.physics_type == 'FLUID': - sub = row.row() - # doesn't work yet - #sub.alert = key.valid - sub.prop(key, "object", text="") - sub.prop(key, "system", text="System") + +class PARTICLE_PT_physics_deflection(ParticleButtonsPanel, Panel): + bl_label = "Deflection" + bl_parent_id = "PARTICLE_PT_physics" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type in {'NEWTON', 'FLUID'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + + layout.enabled = particle_panel_enabled(context, psys) + + col = layout.column() + col.prop(part, "use_size_deflect") + col.prop(part, "use_die_on_collision") + + col.prop(part, "collision_group") + + +class PARTICLE_PT_physics_forces(ParticleButtonsPanel, Panel): + bl_label = "Forces" + bl_parent_id = "PARTICLE_PT_physics" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type == 'NEWTON' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + + layout.enabled = particle_panel_enabled(context, psys) + + col = layout.column() + + col.prop(part, "brownian_factor") + col.prop(part, "drag_factor", slider=True) + col.prop(part, "damping", slider=True) + + +class PARTICLE_PT_physics_integration(ParticleButtonsPanel, Panel): + bl_label = "Integration" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = "PARTICLE_PT_physics" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.physics_type == 'NEWTON' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + + layout.enabled = particle_panel_enabled(context, psys) + + col = layout.column() + + col.prop(part, "integrator") + col.prop(part, "timestep") + sub = col.row() + sub.prop(part, "subframes") + supports_courant = part.physics_type == 'FLUID' + subsub = sub.row() + subsub.enabled = supports_courant + subsub.prop(part, "use_adaptive_subframes", text="") + if supports_courant and part.use_adaptive_subframes: + col.prop(part, "courant_target", text="Threshold") class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): bl_label = "Boid Brain" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = "PARTICLE_PT_physics" + + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): psys = context.particle_system settings = particle_get_settings(context) - engine = context.scene.render.engine + engine = context.engine if settings is None: return False @@ -895,12 +1189,13 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): class PARTICLE_PT_render(ParticleButtonsPanel, Panel): bl_label = "Render" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): settings = particle_get_settings(context) - engine = context.scene.render.engine + engine = context.engine if settings is None: return False @@ -908,257 +1203,453 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True psys = context.particle_system part = particle_get_settings(context) + layout.prop(part, "render_type", text="Render As") + + if part.type == 'EMITTER' or \ + (part.render_type in {'OBJECT', 'COLLECTION'} and part.type == 'HAIR'): + if part.render_type not in {'NONE'}: + + col = layout.column(align=True) + col.prop(part, "particle_size", text="Scale") + col.prop(part, "size_random", slider=True, text="Scale Randomness") + if psys: - row = layout.row() - if part.render_type in {'OBJECT', 'GROUP'}: - row.enabled = False - row.prop(part, "material_slot", text="") - row.prop(psys, "parent") + col = layout.column() + if part.render_type not in {'OBJECT', 'COLLECTION', 'NONE'}: + # col.enabled = False + col.prop(part, "material_slot", text="Material") + col.prop(psys, "parent", text="Coordinate System") - split = layout.split() - col = split.column() - col.prop(part, "use_render_emitter") - col.prop(part, "use_parent_particles") +class PARTICLE_PT_render_extra(ParticleButtonsPanel, Panel): + bl_label = "Extra" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - col = split.column() - col.prop(part, "show_unborn") - col.prop(part, "use_dead") + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type != 'NONE' - layout.row().prop(part, "render_type", expand=True) + def draw(self, context): + layout = self.layout + layout.use_property_split = True - split = layout.split() + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) - col = split.column() + col = layout.column() - if part.render_type == 'LINE': - col.prop(part, "line_length_tail") - col.prop(part, "line_length_head") + col = layout.column() + col.prop(part, "use_parent_particles", text="Parent Particles") + col.prop(part, "show_unborn", text="Unborn") + col.prop(part, "use_dead", text="Dead") - split.prop(part, "use_velocity_length") - elif part.render_type == 'PATH': - col.prop(part, "use_strand_primitive") - sub = col.column() - sub.active = (part.use_strand_primitive is False) - sub.prop(part, "use_render_adaptive") - sub = col.column() - sub.active = part.use_render_adaptive or part.use_strand_primitive is True - sub.prop(part, "adaptive_angle") - sub = col.column() - sub.active = (part.use_render_adaptive is True and part.use_strand_primitive is False) - sub.prop(part, "adaptive_pixel") - col.prop(part, "use_hair_bspline") - col.prop(part, "render_step", text="Steps") - col = split.column() - col.label(text="Timing:") - col.prop(part, "use_absolute_path_time") +class PARTICLE_PT_render_line(ParticleButtonsPanel, Panel): + bl_label = "Line" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - if part.type == 'HAIR' or psys.point_cache.is_baked: - col.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time) - else: - col.prop(part, "trail_count") + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'LINE' - col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time) - col.prop(part, "length_random", text="Random", slider=True) + def draw(self, context): + layout = self.layout + layout.use_property_split = True - row = layout.row() - col = row.column() - - if part.type == 'HAIR' and part.use_strand_primitive is True and part.child_type == 'INTERPOLATED': - layout.prop(part, "use_simplify") - if part.use_simplify is True: - row = layout.row() - row.prop(part, "simplify_refsize") - row.prop(part, "simplify_rate") - row.prop(part, "simplify_transition") - row = layout.row() - row.prop(part, "use_simplify_viewport") - sub = row.row() - sub.active = part.use_simplify_viewport is True - sub.prop(part, "simplify_viewport") - - elif part.render_type == 'OBJECT': - col.prop(part, "dupli_object") - sub = col.row() - sub.prop(part, "use_global_dupli") - sub.prop(part, "use_rotation_dupli") - sub.prop(part, "use_scale_dupli") - elif part.render_type == 'GROUP': - col.prop(part, "dupli_group") - split = layout.split() + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) - col = split.column() - col.prop(part, "use_whole_group") - sub = col.column() - sub.active = (part.use_whole_group is False) - sub.prop(part, "use_group_pick_random") - sub.prop(part, "use_group_count") + col = layout.column() - col = split.column() - sub = col.column() - sub.active = (part.use_whole_group is False) - sub.prop(part, "use_global_dupli") - sub.prop(part, "use_rotation_dupli") - sub.prop(part, "use_scale_dupli") + col.separator() + sub = col.column(align=True) + sub.prop(part, "line_length_tail", text="Length Tail") + sub.prop(part, "line_length_head", text="Head") + col.prop(part, "use_velocity_length", text="Velocity Length") - if part.use_group_count and not part.use_whole_group: - row = layout.row() - row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights", - part, "active_dupliweight_index") - col = row.column() - sub = col.row() - subsub = sub.column(align=True) - subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="") - subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="") - subsub.operator("particle.dupliob_move_up", icon='TRIA_UP', text="") - subsub.operator("particle.dupliob_move_down", icon='TRIA_DOWN', text="") +class PARTICLE_PT_render_path(ParticleButtonsPanel, Panel): + bl_label = "Path" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - weight = part.active_dupliweight - if weight: - row = layout.row() - row.prop(weight, "count") + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'PATH' - elif part.render_type == 'BILLBOARD': - ob = context.object + def draw(self, context): + layout = self.layout + layout.use_property_split = True - col.label(text="Align:") + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) - row = layout.row() - row.prop(part, "billboard_align", expand=True) - row.prop(part, "lock_billboard", text="Lock") - row = layout.row() - row.prop(part, "billboard_object") + col = layout.column() - row = layout.row() - col = row.column(align=True) - col.label(text="Tilt:") - col.prop(part, "billboard_tilt", text="Angle", slider=True) - col.prop(part, "billboard_tilt_random", text="Random", slider=True) - col = row.column() - col.prop(part, "billboard_offset") + col.prop(part, "use_strand_primitive") + sub = col.column() + sub.active = (part.use_strand_primitive is False) + sub.prop(part, "use_render_adaptive") + sub = col.column() + sub.active = part.use_render_adaptive or part.use_strand_primitive is True + sub.prop(part, "adaptive_angle") + sub = col.column() + sub.active = (part.use_render_adaptive is True and part.use_strand_primitive is False) + sub.prop(part, "adaptive_pixel") + col.prop(part, "use_hair_bspline") + col.prop(part, "render_step", text="Steps") + + +class PARTICLE_PT_render_path_timing(ParticleButtonsPanel, Panel): + bl_label = "Timing" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - row = layout.row() - col = row.column() - col.prop(part, "billboard_size", text="Scale") - if part.billboard_align == 'VEL': - col = row.column(align=True) - col.label("Velocity Scale:") - col.prop(part, "billboard_velocity_head", text="Head") - col.prop(part, "billboard_velocity_tail", text="Tail") + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'PATH' - if psys: - col = layout.column() - col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_textures") - col.prop_search(psys, "billboard_time_index_uv", ob.data, "uv_textures") + def draw(self, context): + layout = self.layout + layout.use_property_split = True - split = layout.split(percentage=0.33) - split.label(text="Split UVs:") - split.prop(part, "billboard_uv_split", text="Number of splits") + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) - if psys: - col = layout.column() - col.active = part.billboard_uv_split > 1 - col.prop_search(psys, "billboard_split_uv", ob.data, "uv_textures") + col = layout.column() - row = col.row() - row.label(text="Animate:") - row.prop(part, "billboard_animation", text="") - row.label(text="Offset:") - row.prop(part, "billboard_offset_split", text="") + col.prop(part, "use_absolute_path_time") - if part.render_type == 'HALO' or part.render_type == 'LINE' or part.render_type == 'BILLBOARD': - row = layout.row() - col = row.column() + if part.type == 'HAIR' or psys.point_cache.is_baked: + col.prop(part, "path_start", text="Start", slider=not part.use_absolute_path_time) + else: col.prop(part, "trail_count") - if part.trail_count > 1: - col.prop(part, "use_absolute_path_time", text="Length in Frames") - col = row.column() - col.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time) - col.prop(part, "length_random", text="Random", slider=True) - else: - col = row.column() - col.label(text="") - if part.type == 'EMITTER' or \ - (part.render_type in {'OBJECT', 'GROUP'} and part.type == 'HAIR'): - row = layout.row(align=True) - row.prop(part, "particle_size") - row.prop(part, "size_random", slider=True) + col.prop(part, "path_end", text="End", slider=not part.use_absolute_path_time) + col.prop(part, "length_random", text="Random", slider=True) + + +class PARTICLE_PT_render_object(ParticleButtonsPanel, Panel): + bl_label = "Object" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'OBJECT' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) + + col = layout.column() + + col.prop(part, "dupli_object", text="Instance Object") + sub = col.column() + sub.prop(part, "use_global_dupli", text="Global Coordinates") + sub.prop(part, "use_rotation_dupli", text="Object Rotation") + sub.prop(part, "use_scale_dupli", text="Object Scale") + + +class PARTICLE_PT_render_collection(ParticleButtonsPanel, Panel): + bl_label = "Collection" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'COLLECTION' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) + + col = layout.column() + + col.prop(part, "dupli_group") + + col.prop(part, "use_whole_group") + sub = col.column() + sub.active = (part.use_whole_group is False) + sub.prop(part, "use_group_pick_random") + sub.prop(part, "use_global_dupli", text="Global Coordinates") + sub.prop(part, "use_rotation_dupli", text="Object Rotation") + sub.prop(part, "use_scale_dupli", text="Object Scale") + + +class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel): + bl_label = "Use Count" + bl_parent_id = "PARTICLE_PT_render_collection" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'COLLECTION' + + def draw_header(self, context): + layout = self.layout + part = particle_get_settings(context) + + layout.active = not part.use_whole_group + + layout.prop(part, "use_group_count", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) + + col = layout.column() + + layout.active = part.use_group_count and not part.use_whole_group + + row = layout.row() + row.template_list("UI_UL_list", "particle_dupli_weights", part, "dupli_weights", + part, "active_dupliweight_index") + + col = row.column() + sub = col.row() + subsub = sub.column(align=True) + subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="") + subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="") + subsub.operator("particle.dupliob_move_up", icon='TRIA_UP', text="") + subsub.operator("particle.dupliob_move_down", icon='TRIA_DOWN', text="") + subsub.separator() + subsub.operator("particle.dupliob_refresh", icon='FILE_REFRESH', text="") + + weight = part.active_dupliweight + if weight: + row = layout.row() + row.prop(weight, "count") + + +class PARTICLE_PT_render_billboards_alignment(ParticleButtonsPanel, Panel): + bl_label = "Billboard Alignment" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'BILLBOARD' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) + + col = layout.column() + + col.prop(part, "billboard_align", text="Align To") + col.prop(part, "lock_billboard", text="Lock Axis") + col.prop(part, "billboard_object") + + +class PARTICLE_PT_render_billboards_tilt(ParticleButtonsPanel, Panel): + bl_label = "Billboard Tilt" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'BILLBOARD' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) + + col = layout.column() + + sub = col.column(align=True) + sub.prop(part, "billboard_tilt", text="Angle", slider=True) + sub.prop(part, "billboard_tilt_random", text="Random", slider=True) + + sub = col.column(align=True) + sub.prop(part, "billboard_offset") + col.prop(part, "billboard_size", text="Scale") + if part.billboard_align == 'VEL': + col = col.column(align=True) + col.prop(part, "billboard_velocity_head", text="Velocity ScaleHead") + col.prop(part, "billboard_velocity_tail", text="Tail") + + +class PARTICLE_PT_render_billboards_uv(ParticleButtonsPanel, Panel): + bl_label = "Billboard UVs" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type == 'BILLBOARD' + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + ob = context.object + part = particle_get_settings(context) + + col = layout.column() + + if psys: + col.prop_search(psys, "billboard_normal_uv", ob.data, "uv_layers") + col.prop_search(psys, "billboard_time_index_uv", ob.data, "uv_layers") + + col.prop(part, "billboard_uv_split", text="Split UVs") + + if psys: + sub = col.column() + sub.active = part.billboard_uv_split > 1 + sub.prop_search(psys, "billboard_split_uv", ob.data, "uv_layers") + + sub.prop(part, "billboard_animation") + sub.prop(part, "billboard_offset_split") + + +class PARTICLE_PT_render_trails(ParticleButtonsPanel, Panel): + bl_label = "Trails" + bl_parent_id = "PARTICLE_PT_render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.render_type in {'HALO', 'LINE', 'BILLBOARD'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = particle_get_settings(context) + + col = layout.column() + + col.prop(part, "trail_count") + + sub = col.column() + sub.active = (part.trail_count > 1) + sub.prop(part, "use_absolute_path_time", text="Length in Frames") + sub.prop(part, "path_end", text="Length", slider=not part.use_absolute_path_time) + sub.prop(part, "length_random", text="Random Length", slider=True) class PARTICLE_PT_draw(ParticleButtonsPanel, Panel): - bl_label = "Display" + bl_label = "Viewport Display" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): settings = particle_get_settings(context) - engine = context.scene.render.engine + engine = context.engine if settings is None: return False return engine in cls.COMPAT_ENGINES def draw(self, context): layout = self.layout + layout.use_property_split = True psys = context.particle_system part = particle_get_settings(context) - row = layout.row() - row.prop(part, "draw_method", expand=True) - row.prop(part, "show_guide_hairs") + layout.prop(part, "draw_method", text="Display As") if part.draw_method == 'NONE' or (part.render_type == 'NONE' and part.draw_method == 'RENDER'): return path = (part.render_type == 'PATH' and part.draw_method == 'RENDER') or part.draw_method == 'PATH' - row = layout.row() - row.prop(part, "draw_percentage", slider=True) + layout.separator() + + col = layout.column() + col.prop(part, "draw_color", text="Color") + if part.draw_color in {'VELOCITY', 'ACCELERATION'}: + col.prop(part, "color_maximum", text="Fade Distance") + + col = layout.column() + + if path: + col.prop(part, "draw_step", text="Strand Steps") + col.prop(part, "draw_percentage", slider=True, text="Amount") if part.draw_method != 'RENDER' or part.render_type == 'HALO': - row.prop(part, "draw_size") - else: - row.label(text="") + col.prop(part, "draw_size", text="Size") if part.draw_percentage != 100 and psys is not None: if part.type == 'HAIR': if psys.use_hair_dynamics and psys.point_cache.is_baked is False: - layout.row().label(text="Display percentage makes dynamics inaccurate without baking!") + layout.row().label(text="Display percentage makes dynamics inaccurate without baking") else: phystype = part.physics_type if phystype != 'NO' and phystype != 'KEYED' and psys.point_cache.is_baked is False: - layout.row().label(text="Display percentage makes dynamics inaccurate without baking!") + layout.row().label(text="Display percentage makes dynamics inaccurate without baking") + else: + layout.row().label(text="") - row = layout.row() - col = row.column() + col = layout.column() + col.prop(part, "show_guide_hairs", text="Guide Hairs") col.prop(part, "show_size") col.prop(part, "show_velocity") col.prop(part, "show_number") if part.physics_type == 'BOIDS': col.prop(part, "show_health") - col = row.column(align=True) - col.label(text="Color:") - col.prop(part, "draw_color", text="") - sub = col.row(align=True) - sub.active = (part.draw_color in {'VELOCITY', 'ACCELERATION'}) - sub.prop(part, "color_maximum", text="Max") - - if path: - col.prop(part, "draw_step") - class PARTICLE_PT_children(ParticleButtonsPanel, Panel): bl_label = "Children" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -1172,37 +1663,91 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel): layout.row().prop(part, "child_type", expand=True) + layout.use_property_split = True + if part.child_type == 'NONE': return - row = layout.row() + col = layout.column() - col = row.column(align=True) - col.prop(part, "child_nbr", text="Display") - col.prop(part, "rendered_child_count", text="Render") + sub = col.column(align=True) + sub.prop(part, "child_nbr", text="Display Amount") + sub.prop(part, "rendered_child_count", text="Render Amount") + + col.separator() + + col.prop(part, "child_length", slider=True) + col.prop(part, "child_length_threshold", slider=True) + if psys: + col.prop(psys, "child_seed", text="Seed") + + col.separator() if part.child_type == 'INTERPOLATED': - col = row.column() - if psys: - col.prop(psys, "child_seed", text="Seed") col.prop(part, "virtual_parents", slider=True) col.prop(part, "create_long_hair_children") else: - col = row.column(align=True) - col.prop(part, "child_size", text="Size") - col.prop(part, "child_size_random", text="Random") + col.separator() + sub = col.column(align=True) + sub.prop(part, "child_size", text="Size") + sub.prop(part, "child_size_random", text="Randomize Size", slider=True) - split = layout.split() + if part.child_type == 'SIMPLE': + col.separator() + col.prop(part, "child_radius", text="Radius") + col.prop(part, "child_roundness", text="Roundness", slider=True) + elif part.virtual_parents > 0.0: + sub = col.column(align=True) + sub.label(text="Parting not available with virtual parents") - col = split.column() - col.label(text="Effects:") - sub = col.column(align=True) - if part.child_type == 'SIMPLE': - sub.prop(part, "twist") - sub.prop(part, "use_twist_curve") - if part.use_twist_curve: - sub.template_curve_mapping(part, "twist_curve") +class PARTICLE_PT_children_parting(ParticleButtonsPanel, Panel): + bl_label = "Parting" + bl_parent_id = "PARTICLE_PT_children" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.child_type == 'INTERPOLATED' + + def draw(self, context): + layout = self.layout + + psys = context.particle_system + part = particle_get_settings(context) + + layout.use_property_split = True + + col = layout.column() + col.prop(part, "child_parting_factor", text="Parting", slider=True) + col.prop(part, "child_parting_min", text="Min") + col.prop(part, "child_parting_max", text="Max") + + +class PARTICLE_PT_children_clumping(ParticleButtonsPanel, Panel): + bl_label = "Clumping" + bl_parent_id = "PARTICLE_PT_children" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.child_type != 'NONE' + + def draw(self, context): + layout = self.layout + + psys = context.particle_system + part = particle_get_settings(context) + + layout.use_property_split = True + + col = layout.column() + + sub = col.column() sub.prop(part, "use_clump_curve") if part.use_clump_curve: @@ -1216,28 +1761,33 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel): subsub.enabled = part.use_clump_noise subsub.prop(part, "clump_noise_size") - sub = col.column(align=True) - sub.prop(part, "child_length", slider=True) - sub.prop(part, "child_length_threshold", slider=True) - if part.child_type == 'SIMPLE': - sub = col.column(align=True) - sub.prop(part, "child_radius", text="Radius") - sub.prop(part, "child_roundness", text="Roundness", slider=True) - if psys: - sub.prop(psys, "child_seed", text="Seed") - elif part.virtual_parents > 0.0: - sub = col.column(align=True) - sub.label(text="Parting not") - sub.label(text="available with") - sub.label(text="virtual parents") - else: - sub = col.column(align=True) - sub.prop(part, "child_parting_factor", text="Parting", slider=True) - sub.prop(part, "child_parting_min", text="Min") - sub.prop(part, "child_parting_max", text="Max") + sub.prop(part, "twist") + sub.prop(part, "use_twist_curve") + if part.use_twist_curve: + sub.template_curve_mapping(part, "twist_curve") + - col = split.column() +class PARTICLE_PT_children_roughness(ParticleButtonsPanel, Panel): + bl_label = "Roughness" + bl_parent_id = "PARTICLE_PT_children" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.child_type != 'NONE' + + def draw(self, context): + layout = self.layout + + psys = context.particle_system + part = particle_get_settings(context) + + layout.use_property_split = True + + col = layout.column() col.prop(part, "use_roughness_curve") if part.use_roughness_curve: @@ -1246,8 +1796,6 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel): sub.prop(part, "roughness_1", text="Roughness") sub.prop(part, "roughness_1_size", text="Size") else: - col.label(text="Roughness:") - sub = col.column(align=True) sub.prop(part, "roughness_1", text="Uniform") sub.prop(part, "roughness_1_size", text="Size") @@ -1261,31 +1809,55 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel): sub.prop(part, "roughness_2_size", text="Size") sub.prop(part, "roughness_2_threshold", slider=True) - layout.row().label(text="Kink:") - layout.row().prop(part, "kink", expand=True) - split = layout.split() - split.active = part.kink != 'NO' +class PARTICLE_PT_children_kink(ParticleButtonsPanel, Panel): + bl_label = "Kink" + bl_parent_id = "PARTICLE_PT_children" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + part = particle_get_settings(context) + return part.child_type != 'NONE' + + def draw(self, context): + layout = self.layout + + psys = context.particle_system + part = particle_get_settings(context) + + layout.use_property_split = True + + col = layout.column() + + col.prop(part, "kink", text="Kink Type") + col = layout.column() + col.active = part.kink != 'NO' if part.kink == 'SPIRAL': - col = split.column() - sub = col.column(align=True) - sub.prop(part, "kink_amplitude", text="Radius") - sub.prop(part, "kink_amplitude_random", text="Random", slider=True) - sub = col.column(align=True) + + sub = col.column() + sub.prop(part, "kink_amplitude", text="Amplitude") + sub.prop(part, "kink_amplitude_random", text="Randomize Amplitude", slider=True) + + col.separator() + + sub = col.column() sub.prop(part, "kink_axis") - sub.prop(part, "kink_axis_random", text="Random", slider=True) - col = split.column(align=True) + sub.prop(part, "kink_axis_random", text="Randomize Axis", slider=True) + + col.separator() + col.prop(part, "kink_frequency", text="Frequency") col.prop(part, "kink_shape", text="Shape", slider=True) col.prop(part, "kink_extra_steps", text="Steps") - else: - col = split.column() + + elif part.kink in {'CURL', 'RADIAL', 'WAVE', 'BRAID', 'WAVE'}: sub = col.column(align=True) sub.prop(part, "kink_amplitude") sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True) col.prop(part, "kink_flat", slider=True) - col = split.column(align=True) col.prop(part, "kink_frequency") col.prop(part, "kink_shape", slider=True) @@ -1293,7 +1865,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel, Panel): class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel): bl_label = "Field Weights" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -1314,41 +1886,85 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel, Panel): class PARTICLE_PT_force_fields(ParticleButtonsPanel, Panel): bl_label = "Force Field Settings" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True part = particle_get_settings(context) - row = layout.row() - row.prop(part, "use_self_effect") - row.prop(part, "effector_amount", text="Amount") + col = layout.column() + col.prop(part, "use_self_effect") + col.prop(part, "effector_amount", text="Effector Amount") + + +class PARTICLE_PT_force_fields_type1(ParticleButtonsPanel, Panel): + bl_label = "Type 1" + bl_parent_id = "PARTICLE_PT_force_fields" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - split = layout.split(percentage=0.2) - split.label(text="Type 1:") - split.prop(part.force_field_1, "type", text="") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + part = particle_get_settings(context) + + col = layout.column() + col.prop(part.force_field_1, "type", text="Type 1") basic_force_field_settings_ui(self, context, part.force_field_1) - if part.force_field_1.type != 'NONE': - layout.label(text="Falloff:") - basic_force_field_falloff_ui(self, context, part.force_field_1) - if part.force_field_1.type != 'NONE': - layout.label(text="") - split = layout.split(percentage=0.2) - split.label(text="Type 2:") - split.prop(part.force_field_2, "type", text="") +class PARTICLE_PT_force_fields_type2(ParticleButtonsPanel, Panel): + bl_label = "Type 2" + bl_parent_id = "PARTICLE_PT_force_fields" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + part = particle_get_settings(context) + + col = layout.column() + col.prop(part.force_field_2, "type", text="Type 2") basic_force_field_settings_ui(self, context, part.force_field_2) - if part.force_field_2.type != 'NONE': - layout.label(text="Falloff:") + + +class PARTICLE_PT_force_fields_type1_falloff(ParticleButtonsPanel, Panel): + bl_label = "Falloff" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = "PARTICLE_PT_force_fields_type1" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + part = particle_get_settings(context) + + basic_force_field_falloff_ui(self, context, part.force_field_1) + + +class PARTICLE_PT_force_fields_type2_falloff(ParticleButtonsPanel, Panel): + bl_label = "Falloff" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = "PARTICLE_PT_force_fields_type2" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + part = particle_get_settings(context) + basic_force_field_falloff_ui(self, context, part.force_field_2) class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel): bl_label = "Vertex Groups" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -1358,6 +1974,7 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object psys = context.particle_system @@ -1417,30 +2034,126 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, Panel): # row.prop(psys, "invert_vertex_group_field", text="") +class PARTICLE_PT_textures(ParticleButtonsPanel, Panel): + bl_label = "Textures" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + if context.particle_system is None: + return False + return particle_panel_poll(cls, context) + + def draw(self, context): + layout = self.layout + + psys = context.particle_system + part = psys.settings + + row = layout.row() + row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2) + + col = row.column(align=True) + col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' + col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN' + col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="") + + if not part.active_texture: + layout.template_ID(part, "active_texture", new="texture.new") + else: + slot = part.texture_slots[part.active_texture_index] + layout.template_ID(slot, "texture", new="texture.new") + + +class PARTICLE_PT_hair_shape(ParticleButtonsPanel, Panel): + bl_label = "Hair Shape" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + if context.particle_system is None: + return False + return particle_panel_poll(cls, context) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + psys = context.particle_system + part = psys.settings + + layout.prop(part, "shape", text="Strand Shape") + + col = layout.column(align=True) + col.prop(part, "root_radius", text="Radius Root") + col.prop(part, "tip_radius", text="Tip") + + col = layout.column() + col.prop(part, "radius_scale", text="Radius Scaling") + col.prop(part, "use_close_tip") + + class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "particle_system.settings" _property_type = bpy.types.ParticleSettings classes = ( PARTICLE_MT_specials, - PARTICLE_MT_hair_dynamics_presets, + PARTICLE_PT_hair_dynamics_presets, PARTICLE_UL_particle_systems, PARTICLE_PT_context_particles, PARTICLE_PT_emission, + PARTICLE_PT_emission_source, PARTICLE_PT_hair_dynamics, + PARTICLE_PT_hair_dynamics_structure, + PARTICLE_PT_hair_dynamics_volume, PARTICLE_PT_cache, PARTICLE_PT_velocity, PARTICLE_PT_rotation, + PARTICLE_PT_rotation_angular_velocity, PARTICLE_PT_physics, + PARTICLE_PT_physics_fluid_springs, + PARTICLE_PT_physics_fluid_springs_viscoelastic, + PARTICLE_PT_physics_fluid_springs_advanced, + PARTICLE_PT_physics_fluid_advanced, + PARTICLE_PT_physics_boids_movement, + PARTICLE_PT_physics_boids_battle, + PARTICLE_PT_physics_boids_misc, + PARTICLE_PT_physics_forces, + PARTICLE_PT_physics_deflection, + PARTICLE_PT_physics_integration, + PARTICLE_PT_physics_relations, PARTICLE_PT_boidbrain, PARTICLE_PT_render, + PARTICLE_PT_render_line, + PARTICLE_PT_render_path, + PARTICLE_PT_render_path_timing, + PARTICLE_PT_render_object, + PARTICLE_PT_render_collection, + PARTICLE_PT_render_collection_use_count, + PARTICLE_PT_render_billboards_tilt, + PARTICLE_PT_render_billboards_uv, + PARTICLE_PT_render_trails, + PARTICLE_PT_render_extra, PARTICLE_PT_draw, PARTICLE_PT_children, + PARTICLE_PT_children_parting, + PARTICLE_PT_children_clumping, + PARTICLE_PT_children_roughness, + PARTICLE_PT_children_kink, + PARTICLE_PT_hair_shape, PARTICLE_PT_field_weights, PARTICLE_PT_force_fields, + PARTICLE_PT_force_fields_type1, + PARTICLE_PT_force_fields_type1_falloff, + PARTICLE_PT_force_fields_type2, + PARTICLE_PT_force_fields_type2_falloff, PARTICLE_PT_vertexgroups, + PARTICLE_PT_textures, PARTICLE_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py index 45cddd3d6b9..0a7318864a3 100644 --- a/release/scripts/startup/bl_ui/properties_physics_cloth.py +++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py @@ -17,8 +17,12 @@ # ##### END GPL LICENSE BLOCK ##### # <pep8 compliant> + import bpy -from bpy.types import Menu, Panel +from bpy.types import ( + Panel, +) +from bl_operators.presets import PresetMenu from .properties_physics_common import ( point_cache_ui, @@ -30,11 +34,11 @@ def cloth_panel_enabled(md): return md.point_cache.is_baked is False -class CLOTH_MT_presets(Menu): +class CLOTH_PT_presets(PresetMenu): bl_label = "Cloth Presets" preset_subdir = "cloth" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "cloth.preset_add" class PhysicButtonsPanel: @@ -45,16 +49,19 @@ class PhysicButtonsPanel: @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.cloth) + return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.cloth) class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel): bl_label = "Cloth" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header_preset(self, context): + CLOTH_PT_presets.draw_panel_header(self.layout) def draw(self, context): layout = self.layout + layout.use_property_split = True md = context.cloth ob = context.object @@ -62,78 +69,89 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, Panel): layout.active = cloth_panel_enabled(md) - split = layout.split(percentage=0.25) + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) - split.label(text="Presets:") - sub = split.row(align=True) - sub.menu("CLOTH_MT_presets", text=bpy.types.CLOTH_MT_presets.bl_label) - sub.operator("cloth.preset_add", text="", icon='ZOOMIN') - sub.operator("cloth.preset_add", text="", icon='ZOOMOUT').remove_active = True + col = flow.column() + col.prop(cloth, "quality", text="Quality Steps") + col.prop(cloth, "time_scale", text="Speed Multiplier") - split = layout.split(percentage=0.25) + col.separator() - split.label(text="Quality:") - split.prop(cloth, "quality", text="Steps") + col = flow.column() + col.prop(cloth, "mass", text="Material Mass") + col.prop(cloth, "structural_stiffness", text="Structural") + col.prop(cloth, "bending_stiffness", text="Bending") - split = layout.split(percentage=0.25) + col.separator() - split.label(text="Speed:") - split.prop(cloth, "time_scale", text="Multiplier") + col = flow.column() + col.prop(cloth, "spring_damping", text="Damping Spring") + col.prop(cloth, "air_damping", text="Air") + col.prop(cloth, "vel_damping", text="Velocity") - split = layout.split() + col = flow.column() + col.prop(cloth, "use_dynamic_mesh", text="Dynamic Mesh") - col = split.column() + key = ob.data.shape_keys - col.label(text="Material:") - col.prop(cloth, "mass") - col.prop(cloth, "structural_stiffness", text="Structural") - col.prop(cloth, "bending_stiffness", text="Bending") + if key: + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.active = not cloth.use_dynamic_mesh + row.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="Rest Shape Key") + row.label(text="", icon='BLANK1') - col = split.column() - col.label(text="Damping:") - col.prop(cloth, "spring_damping", text="Spring") - col.prop(cloth, "air_damping", text="Air") - col.prop(cloth, "vel_damping", text="Velocity") +class PHYSICS_PT_cloth_pinning(PhysicButtonsPanel, Panel): + bl_label = "Pinning" + bl_parent_id = 'PHYSICS_PT_cloth' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - split = layout.split() + def draw_header(self, context): + md = context.cloth + cloth = md.settings - col = split.column() + self.layout.active = cloth_panel_enabled(md) and cloth.use_pin_cloth + self.layout.prop(cloth, "use_pin_cloth", text="") - col.prop(cloth, "use_pin_cloth", text="Pinning:") - sub = col.column() - sub.active = cloth.use_pin_cloth - sub.prop_search(cloth, "vertex_group_mass", ob, "vertex_groups", text="") - sub.prop(cloth, "pin_stiffness", text="Stiffness") + def draw(self, context): + layout = self.layout + layout.use_property_split = True - # Disabled for now - """ - if cloth.vertex_group_mass: - layout.label(text="Goal:") + md = context.cloth + ob = context.object + cloth = md.settings - col = layout.column_flow() - col.prop(cloth, "goal_default", text="Default") - col.prop(cloth, "goal_spring", text="Stiffness") - col.prop(cloth, "goal_friction", text="Friction") - """ + layout.active = cloth_panel_enabled(md) and cloth.use_pin_cloth - col = split.column() + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) - col.prop(cloth, "use_dynamic_mesh", text="Dynamic Mesh") + col = flow.column() - key = ob.data.shape_keys + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(cloth, "vertex_group_mass", ob, "vertex_groups", text="Mass Group") + row.label(text="", icon='BLANK1') - if key: - sub = col.column() - sub.active = not cloth.use_dynamic_mesh - sub.label(text="Rest Shape Key:") - sub.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="") + col = flow.column() + col.prop(cloth, "pin_stiffness", text="Stiffness") + + # Disabled for now. + """ + if cloth.vertex_group_mass: + col = flow.column() + col.prop(cloth, "goal_default", text="Goal Default") + col.prop(cloth, "goal_spring", text="Stiffness") + col.prop(cloth, "goal_friction", text="Friction") + """ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel): - bl_label = "Cloth Cache" + bl_label = "Cache" + bl_parent_id = 'PHYSICS_PT_cloth' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): md = context.cloth @@ -141,9 +159,10 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel, Panel): class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel): - bl_label = "Cloth Collision" + bl_label = "Collision" + bl_parent_id = 'PHYSICS_PT_cloth' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): cloth = context.cloth.collision_settings @@ -153,37 +172,66 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True cloth = context.cloth.collision_settings md = context.cloth - ob = context.object layout.active = cloth.use_collision and cloth_panel_enabled(md) - split = layout.split() + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) - col = split.column() + col = flow.column() col.prop(cloth, "collision_quality", text="Quality") col.prop(cloth, "distance_min", slider=True, text="Distance") col.prop(cloth, "repel_force", slider=True, text="Repel") + + col = flow.column() col.prop(cloth, "distance_repel", slider=True, text="Repel Distance") col.prop(cloth, "friction") + col.prop(cloth, "group") + + +class PHYSICS_PT_cloth_self_collision(PhysicButtonsPanel, Panel): + bl_label = "Self Collision" + bl_parent_id = 'PHYSICS_PT_cloth_collision' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} - col = split.column() - col.prop(cloth, "use_self_collision", text="Self Collision") - sub = col.column() - sub.active = cloth.use_self_collision - sub.prop(cloth, "self_collision_quality", text="Quality") - sub.prop(cloth, "self_distance_min", slider=True, text="Distance") - sub.prop_search(cloth, "vertex_group_self_collisions", ob, "vertex_groups", text="") + def draw_header(self, context): + cloth = context.cloth.collision_settings + + self.layout.active = cloth_panel_enabled(context.cloth) and cloth.use_self_collision + self.layout.prop(cloth, "use_self_collision", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + cloth = context.cloth.collision_settings + md = context.cloth + ob = context.object + + layout.active = cloth.use_collision and cloth_panel_enabled(md) and cloth.use_self_collision - layout.prop(cloth, "group") + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) + + col = flow.column() + col.prop(cloth, "self_collision_quality", text="Quality") + col.prop(cloth, "self_distance_min", slider=True, text="Distance") + + col = flow.column() + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(cloth, "vertex_group_self_collisions", ob, "vertex_groups", text="Vertex Group") + row.label(text="", icon='BLANK1') class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel): - bl_label = "Cloth Stiffness Scaling" + bl_label = "Stiffness Scaling" + bl_parent_id = 'PHYSICS_PT_cloth' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): cloth = context.cloth.settings @@ -193,6 +241,7 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True md = context.cloth ob = context.object @@ -200,23 +249,35 @@ class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel, Panel): layout.active = (cloth.use_stiffness_scale and cloth_panel_enabled(md)) - split = layout.split() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - col = split.column() - col.label(text="Structural Stiffness:") - col.prop_search(cloth, "vertex_group_structural_stiffness", ob, "vertex_groups", text="") + col = flow.column() + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search( + cloth, "vertex_group_structural_stiffness", ob, "vertex_groups", + text="Structural Group" + ) + row.label(text="", icon='BLANK1') col.prop(cloth, "structural_stiffness_max", text="Max") - col = split.column() - col.label(text="Bending Stiffness:") - col.prop_search(cloth, "vertex_group_bending", ob, "vertex_groups", text="") + col.separator() + + col = flow.column() + row = col.row(align=True) + row.prop_search( + cloth, "vertex_group_bending", ob, "vertex_groups", + text="Bending Group" + ) + row.label(text="", icon='BLANK1') col.prop(cloth, "bending_stiffness_max", text="Max") class PHYSICS_PT_cloth_sewing(PhysicButtonsPanel, Panel): - bl_label = "Cloth Sewing Springs" + bl_label = "Sewing Springs" + bl_parent_id = 'PHYSICS_PT_cloth' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): cloth = context.cloth.settings @@ -226,31 +287,36 @@ class PHYSICS_PT_cloth_sewing(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True md = context.cloth ob = context.object cloth = context.cloth.settings layout.active = (cloth.use_sewing_springs and cloth_panel_enabled(md)) + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - layout.prop(cloth, "sewing_force_max", text="Sewing Force") + col = flow.column() + col.prop(cloth, "sewing_force_max", text="Sewing Force") - split = layout.split() + col.separator() - col = split.column(align=True) - col.label(text="Shrinking:") - col.prop_search(cloth, "vertex_group_shrink", ob, "vertex_groups", text="") + col = col.column() + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(cloth, "vertex_group_shrink", ob, "vertex_groups", text="Shrinking Group") + row.label(text="", icon='BLANK1') - col = split.column(align=True) - col.label() + col = flow.column(align=True) col.prop(cloth, "shrink_min", text="Min") col.prop(cloth, "shrink_max", text="Max") class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel): - bl_label = "Cloth Field Weights" + bl_label = "Field Weights" + bl_parent_id = 'PHYSICS_PT_cloth' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): cloth = context.cloth.settings @@ -258,10 +324,12 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, Panel): classes = ( - CLOTH_MT_presets, + CLOTH_PT_presets, PHYSICS_PT_cloth, PHYSICS_PT_cloth_cache, PHYSICS_PT_cloth_collision, + PHYSICS_PT_cloth_self_collision, + PHYSICS_PT_cloth_pinning, PHYSICS_PT_cloth_stiffness, PHYSICS_PT_cloth_sewing, PHYSICS_PT_cloth_field_weights, diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index b821b20a1ae..2da84ad84da 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -30,8 +30,7 @@ class PhysicButtonsPanel: @classmethod def poll(cls, context): - rd = context.scene.render - return (context.object) and rd.engine in cls.COMPAT_ENGINES + return (context.object) and context.engine in cls.COMPAT_ENGINES def physics_add(self, layout, md, name, type, typeicon, toggles): @@ -57,7 +56,7 @@ def physics_add_special(self, layout, data, name, addop, removeop, typeicon): class PHYSICS_PT_add(PhysicButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): obj = context.object @@ -98,7 +97,7 @@ class PHYSICS_PT_add(PhysicButtonsPanel, Panel): 'CONSTRAINT') # RB_TODO needs better icon -# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc +# cache-type can be 'PSYS' 'HAIR' 'SMOKE' etc. def point_cache_ui(self, context, cache, enabled, cachetype): layout = self.layout @@ -113,8 +112,8 @@ def point_cache_ui(self, context, cache, enabled, cachetype): col.operator("ptcache.add", icon='ZOOMIN', text="") col.operator("ptcache.remove", icon='ZOOMOUT', text="") - row = layout.row() if cachetype in {'PSYS', 'HAIR', 'SMOKE'}: + row = layout.row() row.prop(cache, "use_external") if cachetype == 'SMOKE': @@ -132,7 +131,9 @@ def point_cache_ui(self, context, cache, enabled, cachetype): cache_info = cache.info if cache_info: - layout.label(text=cache_info) + col = layout.column() + col.alignment = 'RIGHT' + col.label(text=cache_info) else: if cachetype in {'SMOKE', 'DYNAMIC_PAINT'}: if not bpy.data.is_saved: @@ -140,51 +141,62 @@ def point_cache_ui(self, context, cache, enabled, cachetype): layout.enabled = False if not cache.use_external or cachetype == 'SMOKE': - row = layout.row(align=True) + col = layout.column(align=True) + col.use_property_split = True if cachetype not in {'PSYS', 'DYNAMIC_PAINT'}: - row.enabled = enabled - row.prop(cache, "frame_start") - row.prop(cache, "frame_end") + + col.enabled = enabled + col.prop(cache, "frame_start", text="Simulation Start") + col.prop(cache, "frame_end") + if cachetype not in {'SMOKE', 'CLOTH', 'DYNAMIC_PAINT', 'RIGID_BODY'}: - row.prop(cache, "frame_step") + col.prop(cache, "frame_step") - if cachetype != 'SMOKE': - layout.label(text=cache.info) + cache_info = cache.info + if cachetype != 'SMOKE' and cache_info: # avoid empty space. + col = layout.column(align=True) + col.alignment = 'RIGHT' + col.label(text=cache_info) can_bake = True if cachetype not in {'SMOKE', 'DYNAMIC_PAINT', 'RIGID_BODY'}: - split = layout.split() - split.enabled = enabled and bpy.data.is_saved + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + flow.enabled = enabled and bpy.data.is_saved - col = split.column() - col.prop(cache, "use_disk_cache") + flow.use_property_split = True - col = split.column() - col.active = cache.use_disk_cache - col.prop(cache, "use_library_path", "Use Lib Path") + # NOTE: TODO temporarly used until the animate properties are properly skipped. + flow.use_property_decorate = False # No animation (remove this later on) + + col = flow.column() + col.prop(cache, "use_disk_cache") - row = layout.row() - row.enabled = enabled and bpy.data.is_saved - row.active = cache.use_disk_cache - row.label(text="Compression:") - row.prop(cache, "compression", expand=True) + subcol = col.column() + subcol.active = cache.use_disk_cache + subcol.prop(cache, "use_library_path", "Use Lib Path") - layout.separator() + col = flow.column() + col.enabled = enabled and bpy.data.is_saved + col.active = cache.use_disk_cache + col.prop(cache, "compression", text="Compression", expand=True) if cache.id_data.library and not cache.use_disk_cache: can_bake = False col = layout.column(align=True) - col.label(text="Linked object baking requires Disk Cache to be enabled", icon='INFO') + col.alignment = 'RIGHT' + + col.separator() + + col.label(text="Linked object baking requires Disk Cache to be enabled") else: layout.separator() - split = layout.split() - split.active = can_bake - - col = split.column() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + col = flow.column() + col.active = can_bake if cache.is_baked is True: col.operator("ptcache.free_bake", text="Free Bake") @@ -199,7 +211,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype): sub.enabled = enabled sub.operator("ptcache.bake_from_cache", text="Current Cache to Bake") - col = split.column() + col = flow.column() col.operator("ptcache.bake_all", text="Bake All Dynamics").bake = True col.operator("ptcache.free_bake_all", text="Free All Bakes") col.operator("ptcache.bake_all", text="Update All To Frame").bake = False @@ -207,32 +219,35 @@ def point_cache_ui(self, context, cache, enabled, cachetype): def effector_weights_ui(self, context, weights, weight_type): layout = self.layout + layout.use_property_split = True layout.prop(weights, "group") - split = layout.split() - - split.prop(weights, "gravity", slider=True) - split.prop(weights, "all", slider=True) + # NOTE: TODO temporarly used until the animate properties are properly skipped + layout.use_property_decorate = False # No animation (remove this later on) - layout.separator() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - split = layout.split() - - col = split.column() + col = flow.column() + col.prop(weights, "gravity", slider=True) + col.prop(weights, "all", slider=True) col.prop(weights, "force", slider=True) col.prop(weights, "vortex", slider=True) + + col = flow.column() col.prop(weights, "magnetic", slider=True) + col.prop(weights, "harmonic", slider=True) + col.prop(weights, "charge", slider=True) + col.prop(weights, "lennardjones", slider=True) + + col = flow.column() col.prop(weights, "wind", slider=True) col.prop(weights, "curve_guide", slider=True) col.prop(weights, "texture", slider=True) if weight_type != 'SMOKE': col.prop(weights, "smokeflow", slider=True) - col = split.column() - col.prop(weights, "harmonic", slider=True) - col.prop(weights, "charge", slider=True) - col.prop(weights, "lennardjones", slider=True) + col = flow.column() col.prop(weights, "turbulence", slider=True) col.prop(weights, "drag", slider=True) col.prop(weights, "boid", slider=True) @@ -240,13 +255,12 @@ def effector_weights_ui(self, context, weights, weight_type): def basic_force_field_settings_ui(self, context, field): layout = self.layout - - split = layout.split() + layout.use_property_split = True if not field or field.type == 'NONE': return - col = split.column() + col = layout.column() if field.type == 'DRAG': col.prop(field, "linear_drag", text="Linear") @@ -266,10 +280,10 @@ def basic_force_field_settings_ui(self, context, field): else: col.prop(field, "flow") - col = split.column() + col = layout.column() sub = col.column(align=True) sub.prop(field, "noise") - sub.prop(field, "seed") + sub.prop(field, "seed", text="Noise Seed") if field.type == 'TURBULENCE': col.prop(field, "use_global_coords", text="Global") elif field.type == 'HARMONIC': @@ -277,46 +291,33 @@ def basic_force_field_settings_ui(self, context, field): if field.type == 'FORCE': col.prop(field, "use_gravity_falloff", text="Gravitation") - split = layout.split() - - col = split.column() - col.label(text="Effect point:") - col.prop(field, "apply_to_location") - col.prop(field, "apply_to_rotation") - - col = split.column() - col.label(text="Collision:") + col.prop(field, "apply_to_location", text="Affect Location") + col.prop(field, "apply_to_rotation", text="Affect Rotation") col.prop(field, "use_absorption") def basic_force_field_falloff_ui(self, context, field): layout = self.layout - split = layout.split(percentage=0.35) - if not field or field.type == 'NONE': return - col = split.column() - col.prop(field, "z_direction", text="") + col = layout.column() + col.prop(field, "z_direction") - col = split.column() col.prop(field, "falloff_power", text="Power") split = layout.split() - col = split.column() - row = col.row(align=True) - row.prop(field, "use_min_distance", text="") - sub = row.row(align=True) + split.prop(field, "use_min_distance", text="Min Distance") + sub = split.column(align=True) sub.active = field.use_min_distance - sub.prop(field, "distance_min", text="Minimum") + sub.prop(field, "distance_min", text="") - col = split.column() - row = col.row(align=True) - row.prop(field, "use_max_distance", text="") - sub = row.row(align=True) + split = layout.split() + split.prop(field, "use_max_distance", text="Max Distance") + sub = split.column(align=True) sub.active = field.use_max_distance - sub.prop(field, "distance_max", text="Maximum") + sub.prop(field, "distance_max", text="") classes = ( diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py index ef426253a69..3a475c82f5c 100644 --- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py +++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py @@ -55,13 +55,12 @@ class PhysicButtonsPanel: @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return (ob and ob.type == 'MESH') and rd.engine in cls.COMPAT_ENGINES and context.dynamic_paint + return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and context.dynamic_paint class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel): bl_label = "Dynamic Paint" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -88,148 +87,182 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel): col.operator("dpaint.surface_slot_add", icon='ZOOMIN', text="") col.operator("dpaint.surface_slot_remove", icon='ZOOMOUT', text="") + layout.use_property_split = True + if surface: layout.prop(surface, "surface_format") col = layout.column() if surface.surface_format != 'VERTEX': - col.label(text="Quality:") col.prop(surface, "image_resolution") col.prop(surface, "use_antialiasing") - col = layout.column() - col.label(text="Frames:") - split = col.split() - - col = split.column(align=True) - col.prop(surface, "frame_start", text="Start") - col.prop(surface, "frame_end", text="End") + sub = col.column(align=True) + sub.prop(surface, "frame_start", text="Frame Start") + sub.prop(surface, "frame_end", text="End") - split.prop(surface, "frame_substeps") + col.prop(surface, "frame_substeps") elif md.ui_type == 'BRUSH': brush = md.brush_settings - use_shading_nodes = context.scene.render.use_shading_nodes if brush is None: layout.operator("dpaint.type_toggle", text="Add Brush").type = 'BRUSH' else: layout.operator("dpaint.type_toggle", text="Remove Brush", icon='X').type = 'BRUSH' - split = layout.split() + layout.use_property_split = True - col = split.column() + col = layout.column() + col.prop(brush, "paint_color") + col.prop(brush, "paint_alpha", text="Alpha", slider=True) + col.prop(brush, "paint_wetness", text="Wetness", slider=True) col.prop(brush, "use_absolute_alpha") col.prop(brush, "use_paint_erase") - col.prop(brush, "paint_wetness", text="Wetness") - - col = split.column() - if not use_shading_nodes: - sub = col.column() - sub.active = (brush.paint_source != 'PARTICLE_SYSTEM') - sub.prop(brush, "use_material") - if brush.use_material and brush.paint_source != 'PARTICLE_SYSTEM' and not use_shading_nodes: - col.prop(brush, "material", text="") - col.prop(brush, "paint_alpha", text="Alpha Factor") - else: - col.prop(brush, "paint_color", text="") - col.prop(brush, "paint_alpha", text="Alpha") class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Advanced" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_label = "Advanced" + bl_parent_id = "PHYSICS_PT_dynamic_paint" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render - return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and rd.engine in cls.COMPAT_ENGINES + return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and context.engine in cls.COMPAT_ENGINES def draw(self, context): layout = self.layout canvas = context.dynamic_paint.canvas_settings surface = canvas.canvas_surfaces.active - surface_type = surface.surface_type + layout.use_property_split = True + layout.prop(surface, "surface_type") + layout.separator() - # dissolve - if surface_type == 'PAINT': - split = layout.split(percentage=0.35) - split.prop(surface, "use_drying", text="Dry:") - - col = split.column() - col.active = surface.use_drying - split = col.split(percentage=0.7) - col = split.column(align=True) - col.prop(surface, "dry_speed", text="Time") - col.prop(surface, "color_dry_threshold") - split.prop(surface, "use_dry_log", text="Slow") - - if surface_type != 'WAVE': - split = layout.split(percentage=0.35) - col = split.column() - if surface_type == 'WEIGHT': - col.prop(surface, "use_dissolve", text="Fade:") - else: - col.prop(surface, "use_dissolve", text="Dissolve:") - col = split.column() - col.active = surface.use_dissolve - split = col.split(percentage=0.7) - split.prop(surface, "dissolve_speed", text="Time") - split.prop(surface, "use_dissolve_log", text="Slow") + col = layout.column() # per type settings if surface_type == 'DISPLACE': - layout.prop(surface, "use_incremental_displace") + col.prop(surface, "use_incremental_displace") if surface.surface_format == 'VERTEX': - row = layout.row() - row.prop(surface, "depth_clamp") - row.prop(surface, "displace_factor") - - elif surface_type == 'WAVE': - layout.prop(surface, "use_wave_open_border") + col.prop(surface, "depth_clamp") + col.prop(surface, "displace_factor") - split = layout.split() + col.separator() - col = split.column(align=True) + elif surface_type == 'WAVE': + col.prop(surface, "use_wave_open_border") col.prop(surface, "wave_timescale") col.prop(surface, "wave_speed") - - col = split.column(align=True) col.prop(surface, "wave_damping") col.prop(surface, "wave_spring") col.prop(surface, "wave_smoothness") - layout.separator() - layout.prop(surface, "brush_group") - row = layout.row() - row.prop(surface, "brush_influence_scale") - row.prop(surface, "brush_radius_scale") + col.separator() + + col.prop(surface, "brush_group") + col.prop(surface, "brush_influence_scale") + col.prop(surface, "brush_radius_scale") + + +class PHYSICS_PT_dp_advanced_canvas_paint_dry(PhysicButtonsPanel, Panel): + bl_label = "Dry" + bl_parent_id = "PHYSICS_PT_dp_advanced_canvas" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + md = context.dynamic_paint + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and surface_type == 'PAINT' and context.engine in cls.COMPAT_ENGINES + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + self.layout.prop(surface, "use_drying", text="") + + def draw(self, context): + layout = self.layout + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + layout.use_property_split = True + + layout.active = surface.use_drying + + col = layout.column() + col.prop(surface, "dry_speed", text="Time") + col.prop(surface, "color_dry_threshold") + col.prop(surface, "use_dry_log", text="Slow") + + +class PHYSICS_PT_dp_advanced_canvas_paint_dissolve(PhysicButtonsPanel, Panel): + bl_label = "Dissolve" + bl_parent_id = "PHYSICS_PT_dp_advanced_canvas" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + md = context.dynamic_paint + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and surface_type != 'WAVE' and context.engine in cls.COMPAT_ENGINES + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + self.layout.prop(surface, "use_dissolve", text="") + + def draw(self, context): + layout = self.layout + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + surface_type = surface.surface_type + + layout.use_property_split = True + + layout.active = surface.use_dissolve + + col = layout.column() + + col.prop(surface, "dissolve_speed", text="Time") + col.prop(surface, "use_dissolve_log", text="Slow") class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Output" + bl_label = "Output" + bl_parent_id = "PHYSICS_PT_dynamic_paint" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render if not (md and md.ui_type == 'CANVAS' and md.canvas_settings): return 0 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active return (surface and (not (surface.surface_format == 'VERTEX' and (surface.surface_type in {'DISPLACE', 'WAVE'}))) and - (rd.engine in cls.COMPAT_ENGINES)) + (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): layout = self.layout + layout.use_property_split = True canvas = context.dynamic_paint.canvas_settings surface = canvas.canvas_surfaces.active @@ -276,7 +309,7 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): # image format outputs if surface.surface_format == 'IMAGE': layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT') - layout.prop_search(surface, "uv_layer", ob.data, "uv_textures", text="UV Map") + layout.prop_search(surface, "uv_layer", ob.data, "uv_layers", text="UV Map") layout.separator() layout.prop(surface, "image_output_path", text="") @@ -307,18 +340,18 @@ class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel): class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Initial Color" + bl_label = "Initial Color" + bl_parent_id = "PHYSICS_PT_dynamic_paint" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render if not (md and md.ui_type == 'CANVAS' and md.canvas_settings): return 0 surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active - return (surface and surface.surface_type == 'PAINT') and (rd.engine in cls.COMPAT_ENGINES) + return (surface and surface.surface_type == 'PAINT') and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout @@ -327,6 +360,8 @@ class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel): surface = canvas.canvas_surfaces.active ob = context.object + layout.use_property_split = True + layout.prop(surface, "init_color_type", expand=False) if surface.init_color_type != 'NONE': layout.separator() @@ -337,77 +372,126 @@ class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel): elif surface.init_color_type == 'TEXTURE': layout.prop(surface, "init_texture") - layout.prop_search(surface, "init_layername", ob.data, "uv_textures", text="UV Map") + layout.prop_search(surface, "init_layername", ob.data, "uv_layers", text="UV Map") elif surface.init_color_type == 'VERTEX_COLOR': layout.prop_search(surface, "init_layername", ob.data, "vertex_colors", text="Color Layer") class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Effects" + bl_label = "Effects" + bl_parent_id = "PHYSICS_PT_dynamic_paint" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render if not (md and md.ui_type == 'CANVAS' and md.canvas_settings): return False surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active - return (surface and surface.surface_type == 'PAINT') and (rd.engine in cls.COMPAT_ENGINES) + return (surface and surface.surface_type == 'PAINT') and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + +class PHYSICS_PT_dp_effects_spread(PhysicButtonsPanel, Panel): + bl_label = "Spread" + bl_parent_id = "PHYSICS_PT_dp_effects" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): canvas = context.dynamic_paint.canvas_settings surface = canvas.canvas_surfaces.active - layout.row().prop(surface, "effect_ui", expand=True) + self.layout.prop(surface, "use_spread", text="") - if surface.effect_ui == 'SPREAD': - layout.prop(surface, "use_spread") + def draw(self, context): + layout = self.layout - row = layout.row() - row.active = surface.use_spread - row.prop(surface, "spread_speed") - row.prop(surface, "color_spread_speed") + layout.use_property_split = True - elif surface.effect_ui == 'DRIP': - layout.prop(surface, "use_drip") + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + layout.active = surface.use_spread - col = layout.column() - col.active = surface.use_drip - effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT') + col = layout.column() - layout.label(text="Surface Movement:") - row = layout.row() - row.prop(surface, "drip_velocity", slider=True) - row.prop(surface, "drip_acceleration", slider=True) + col.prop(surface, "spread_speed") + col.prop(surface, "color_spread_speed") - elif surface.effect_ui == 'SHRINK': - layout.prop(surface, "use_shrink") - row = layout.row() - row.active = surface.use_shrink - row.prop(surface, "shrink_speed") +class PHYSICS_PT_dp_effects_drip(PhysicButtonsPanel, Panel): + bl_label = "Drip" + bl_parent_id = "PHYSICS_PT_dp_effects" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + + self.layout.prop(surface, "use_drip", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + + layout.active = surface.use_drip + + col = layout.column() + col.prop(surface, "drip_velocity", slider=True) + col.prop(surface, "drip_acceleration", slider=True) + + col.separator() + + effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT') + + +class PHYSICS_PT_dp_effects_shrink(PhysicButtonsPanel, Panel): + bl_label = "Shrink" + bl_parent_id = "PHYSICS_PT_dp_effects" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + + self.layout.prop(surface, "use_shrink", text="") + + def draw(self, context): + layout = self.layout + + layout.use_property_split = True + + canvas = context.dynamic_paint.canvas_settings + surface = canvas.canvas_surfaces.active + layout.active = surface.use_shrink + + layout.prop(surface, "shrink_speed") class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Cache" + bl_label = "Cache" + bl_parent_id = "PHYSICS_PT_dynamic_paint" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render return (md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active and md.canvas_settings.canvas_surfaces.active.is_cache_user and - (rd.engine in cls.COMPAT_ENGINES)) + (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active @@ -417,17 +501,18 @@ class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel): class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Source" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_label = "Source" + bl_parent_id = "PHYSICS_PT_dynamic_paint" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render - return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES) + return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True brush = context.dynamic_paint.brush_settings ob = context.object @@ -437,7 +522,7 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): col.prop(brush, "paint_source") if brush.paint_source == 'PARTICLE_SYSTEM': - col.prop_search(brush, "particle_system", ob, "particle_systems", text="") + col.prop_search(brush, "particle_system", ob, "particle_systems") if brush.particle_system: col.label(text="Particle Effect:") sub = col.column() @@ -448,97 +533,118 @@ class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel): if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}: col.prop(brush, "paint_distance", text="Paint Distance") - split = layout.row().split(percentage=0.4) - sub = split.column() + if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}: - sub.prop(brush, "use_proximity_project") + col.prop(brush, "use_proximity_project") if brush.paint_source == 'VOLUME_DISTANCE': - sub.prop(brush, "invert_proximity") - sub.prop(brush, "use_negative_volume") - - sub = split.column() + col.prop(brush, "invert_proximity") + col.prop(brush, "use_negative_volume") if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}: - column = sub.column() - column.active = brush.use_proximity_project - column.prop(brush, "ray_direction") - sub.prop(brush, "proximity_falloff") + sub = col.column() + sub.active = brush.use_proximity_project + sub.prop(brush, "ray_direction") + col.prop(brush, "proximity_falloff") if brush.proximity_falloff == 'RAMP': - col = layout.row().column() + col.separator() col.prop(brush, "use_proximity_ramp_alpha", text="Only Use Alpha") col.template_color_ramp(brush, "paint_ramp", expand=True) class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Velocity" + bl_label = "Velocity" + bl_parent_id = "PHYSICS_PT_dynamic_paint" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render - return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES) + return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True brush = context.dynamic_paint.brush_settings - split = layout.split() - - col = split.column() + col = layout.column() col.prop(brush, "use_velocity_alpha") col.prop(brush, "use_velocity_color") - - split.prop(brush, "use_velocity_depth") + col.prop(brush, "use_velocity_depth") col = layout.column() col.active = (brush.use_velocity_alpha or brush.use_velocity_color or brush.use_velocity_depth) col.prop(brush, "velocity_max") col.template_color_ramp(brush, "velocity_ramp", expand=True) - layout.separator() - row = layout.row() - row.prop(brush, "use_smudge") - sub = row.row() - sub.active = brush.use_smudge - sub.prop(brush, "smudge_strength") + +class PHYSICS_PT_dp_brush_velocity_smudge(PhysicButtonsPanel, Panel): + bl_label = "Smudge" + bl_parent_id = "PHYSICS_PT_dp_brush_velocity" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + md = context.dynamic_paint + return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + brush = context.dynamic_paint.brush_settings + + self.layout.prop(brush, "use_smudge", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + brush = context.dynamic_paint.brush_settings + + layout.active = brush.use_smudge + layout.prop(brush, "smudge_strength", slider=True) class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel): - bl_label = "Dynamic Paint Waves" + bl_label = "Waves" + bl_parent_id = "PHYSICS_PT_dynamic_paint" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.dynamic_paint - rd = context.scene.render - return md and md.ui_type == 'BRUSH' and md.brush_settings and (rd.engine in cls.COMPAT_ENGINES) + return md and md.ui_type == 'BRUSH' and md.brush_settings and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True brush = context.dynamic_paint.brush_settings layout.prop(brush, "wave_type") if brush.wave_type != 'REFLECT': - row = layout.row() - row.prop(brush, "wave_factor") - row.prop(brush, "wave_clamp") + col = layout.column() + col.prop(brush, "wave_factor") + col.prop(brush, "wave_clamp") classes = ( PHYSICS_UL_dynapaint_surfaces, PHYSICS_PT_dynamic_paint, PHYSICS_PT_dp_advanced_canvas, + PHYSICS_PT_dp_advanced_canvas_paint_dry, + PHYSICS_PT_dp_advanced_canvas_paint_dissolve, PHYSICS_PT_dp_canvas_output, PHYSICS_PT_dp_canvas_initial_color, PHYSICS_PT_dp_effects, + PHYSICS_PT_dp_effects_spread, + PHYSICS_PT_dp_effects_drip, + PHYSICS_PT_dp_effects_shrink, PHYSICS_PT_dp_cache, PHYSICS_PT_dp_brush_source, PHYSICS_PT_dp_brush_velocity, + PHYSICS_PT_dp_brush_velocity_smudge, PHYSICS_PT_dp_brush_wave, ) diff --git a/release/scripts/startup/bl_ui/properties_physics_field.py b/release/scripts/startup/bl_ui/properties_physics_field.py index fb3d1631377..1a4e24fbc0c 100644 --- a/release/scripts/startup/bl_ui/properties_physics_field.py +++ b/release/scripts/startup/bl_ui/properties_physics_field.py @@ -33,60 +33,50 @@ class PhysicButtonsPanel: @classmethod def poll(cls, context): - rd = context.scene.render - return (context.object) and (rd.engine in cls.COMPAT_ENGINES) + return (context.object) and (context.engine in cls.COMPAT_ENGINES) class PHYSICS_PT_field(PhysicButtonsPanel, Panel): bl_label = "Force Fields" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return (rd.engine in cls.COMPAT_ENGINES) and (ob.field) and (ob.field.type != 'NONE') + if not ob: + return False + return (context.engine in cls.COMPAT_ENGINES) and (ob.field) and (ob.field.type != 'NONE') def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object field = ob.field - split = layout.split(percentage=0.2) - split.label(text="Type:") - - split.prop(field, "type", text="") + layout.prop(field, "type") if field.type not in {'NONE', 'GUIDE', 'TEXTURE'}: - split = layout.split(percentage=0.2) - split.label(text="Shape:") - split.prop(field, "shape", text="") + layout.prop(field, "shape", text="Shape") elif field.type == 'TEXTURE': - split = layout.split(percentage=0.2) - split.label(text="Texture:") - split.row().template_ID(field, "texture", new="texture.new") - - split = layout.split() + layout.row().template_ID(field, "texture", new="texture.new") if field.type == 'NONE': return # nothing to draw elif field.type == 'GUIDE': - col = split.column() + col = layout.column() col.prop(field, "guide_minimum") col.prop(field, "guide_free") col.prop(field, "falloff_power") col.prop(field, "use_guide_path_add") col.prop(field, "use_guide_path_weight") - col = split.column() - col.label(text="Clumping:") + col.label(text="Clumping") col.prop(field, "guide_clump_amount") col.prop(field, "guide_clump_shape") - row = layout.row() - row.prop(field, "use_max_distance") - sub = row.row() + col.prop(field, "use_max_distance") + sub = col.column() sub.active = field.use_max_distance sub.prop(field, "distance_max") @@ -96,94 +86,96 @@ class PHYSICS_PT_field(PhysicButtonsPanel, Panel): if field.guide_kink_type != 'NONE': layout.prop(field, "guide_kink_axis") - split = layout.split() - - col = split.column() + col = layout.column() col.prop(field, "guide_kink_frequency") col.prop(field, "guide_kink_shape") - - col = split.column() col.prop(field, "guide_kink_amplitude") elif field.type == 'TEXTURE': - col = split.column() + col = layout.column() col.prop(field, "strength") - col.prop(field, "texture_mode", text="") + col.prop(field, "texture_mode") col.prop(field, "texture_nabla") - col = split.column() col.prop(field, "use_object_coords") col.prop(field, "use_2d_force") elif field.type == 'SMOKE_FLOW': - col = split.column() + col = layout.column() col.prop(field, "strength") col.prop(field, "flow") - col = split.column() - col.label(text="Domain Object:") - col.prop(field, "source_object", "") + col.prop(field, "source_object") col.prop(field, "use_smoke_density") else: basic_force_field_settings_ui(self, context, field) - if field.type not in {'NONE', 'GUIDE'}: - layout.label(text="Falloff:") - layout.row().prop(field, "falloff_type", expand=True) +class PHYSICS_PT_field_falloff(PhysicButtonsPanel, Panel): + bl_label = "Falloff" + bl_parent_id = "PHYSICS_PT_field" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + ob = context.object + return (context.engine in cls.COMPAT_ENGINES) and (ob.field) and (ob.field.type not in {'NONE', 'GUIDE'}) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + field = ob.field - basic_force_field_falloff_ui(self, context, field) + layout.prop(field, "falloff_type", text="Shape") - if field.falloff_type == 'CONE': - layout.separator() + basic_force_field_falloff_ui(self, context, field) - split = layout.split(percentage=0.35) + if field.falloff_type == 'CONE': + layout.separator() - col = split.column() - col.label(text="Angular:") - col.prop(field, "use_radial_min", text="Use Minimum") - col.prop(field, "use_radial_max", text="Use Maximum") + col = layout.column() + col.prop(field, "radial_falloff", text="Power") - col = split.column() - col.prop(field, "radial_falloff", text="Power") + col.label(text="Angular") - sub = col.column() - sub.active = field.use_radial_min - sub.prop(field, "radial_min", text="Angle") + col.prop(field, "use_radial_min", text="Use Min Angle") + sub = col.column() + sub.active = field.use_radial_min + sub.prop(field, "radial_min", text="Min Angle") - sub = col.column() - sub.active = field.use_radial_max - sub.prop(field, "radial_max", text="Angle") + col.prop(field, "use_radial_max", text="Use Max Angle") + sub = col.column() + sub.active = field.use_radial_max + sub.prop(field, "radial_max", text="Max Angle") - elif field.falloff_type == 'TUBE': - layout.separator() + elif field.falloff_type == 'TUBE': + layout.separator() - split = layout.split(percentage=0.35) + col = layout.column() - col = split.column() - col.label(text="Radial:") - col.prop(field, "use_radial_min", text="Use Minimum") - col.prop(field, "use_radial_max", text="Use Maximum") + col.prop(field, "radial_falloff", text="Power") - col = split.column() - col.prop(field, "radial_falloff", text="Power") + col.label(text="Radial") - sub = col.column() - sub.active = field.use_radial_min - sub.prop(field, "radial_min", text="Distance") + col.prop(field, "use_radial_min", text="Use Minimum") + sub = col.column() + sub.active = field.use_radial_min + sub.prop(field, "radial_min", text="Distance") - sub = col.column() - sub.active = field.use_radial_max - sub.prop(field, "radial_max", text="Distance") + col.prop(field, "use_radial_max", text="Use Maximum") + sub = col.column() + sub.active = field.use_radial_max + sub.prop(field, "radial_max", text="Distance") class PHYSICS_PT_collision(PhysicButtonsPanel, Panel): bl_label = "Collision" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.collision) + return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.collision) def draw(self, context): layout = self.layout @@ -191,6 +183,7 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, Panel): md = context.collision split = layout.split() + layout.use_property_split = True coll = md.settings @@ -199,39 +192,90 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, Panel): layout.active = settings.use - split = layout.split() + col = layout.column() + col.prop(settings, "absorption", text="Force Field Absorption") + + +class PHYSICS_PT_collision_particle(PhysicButtonsPanel, Panel): + bl_label = "Particle" + bl_parent_id = "PHYSICS_PT_collision" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.collision) + + def draw(self, context): + layout = self.layout + + md = context.collision - col = split.column() - col.label(text="Particle:") + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + coll = md.settings + + if coll: + settings = context.object.collision + + layout.active = settings.use + + col = flow.column() col.prop(settings, "permeability", slider=True) col.prop(settings, "stickiness") + col = flow.column() col.prop(settings, "use_particle_kill") - col.label(text="Particle Damping:") - sub = col.column(align=True) - sub.prop(settings, "damping_factor", text="Factor", slider=True) - sub.prop(settings, "damping_random", text="Random", slider=True) - col.label(text="Particle Friction:") + col = flow.column() sub = col.column(align=True) - sub.prop(settings, "friction_factor", text="Factor", slider=True) - sub.prop(settings, "friction_random", text="Random", slider=True) + sub.prop(settings, "damping_factor", text="Damping", slider=True) + sub.prop(settings, "damping_random", text="Randomize", slider=True) - col = split.column() - col.label(text="Soft Body and Cloth:") + col = flow.column() sub = col.column(align=True) - sub.prop(settings, "thickness_outer", text="Outer", slider=True) - sub.prop(settings, "thickness_inner", text="Inner", slider=True) + sub.prop(settings, "friction_factor", text="Friction", slider=True) + sub.prop(settings, "friction_random", text="Randomize", slider=True) + + +class PHYSICS_PT_collision_softbody(PhysicButtonsPanel, Panel): + bl_label = "Softbody" + bl_parent_id = "PHYSICS_PT_collision" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.collision) + + def draw(self, context): + layout = self.layout + + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) + + md = context.collision + coll = md.settings + + if coll: + settings = context.object.collision + + layout.active = settings.use - col.label(text="Soft Body Damping:") - col.prop(settings, "damping", text="Factor", slider=True) + col = flow.column() + col.prop(settings, "damping", text="Damping", slider=True) - col.label(text="Force Fields:") - col.prop(settings, "absorption", text="Absorption") + col = flow.column() + col.prop(settings, "thickness_outer", text="Thickness Outer", slider=True) + col.prop(settings, "thickness_inner", text="Inner", slider=True) classes = ( PHYSICS_PT_field, + PHYSICS_PT_field_falloff, PHYSICS_PT_collision, + PHYSICS_PT_collision_particle, + PHYSICS_PT_collision_softbody, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index ab92370f9ae..94611808059 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -20,13 +20,14 @@ import bpy from bpy.types import Panel, Menu from bpy.app.translations import pgettext_iface as iface_ +from bl_operators.presets import PresetMenu -class FLUID_MT_presets(Menu): +class FLUID_PT_presets(PresetMenu): bl_label = "Fluid Presets" preset_subdir = "fluid" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "fluid.preset_add" class PhysicButtonsPanel: @@ -37,13 +38,12 @@ class PhysicButtonsPanel: @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return (ob and ob.type == 'MESH') and rd.engine in cls.COMPAT_ENGINES and (context.fluid) + return (ob and ob.type == 'MESH') and context.engine in cls.COMPAT_ENGINES and (context.fluid) class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel): bl_label = "Fluid" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout @@ -204,15 +204,15 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel): class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel): - bl_label = "Fluid World" + bl_label = "World" + bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} @classmethod def poll(cls, context): md = context.fluid - rd = context.scene.render - return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES + return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES def draw(self, context): layout = self.layout @@ -242,11 +242,7 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel): col.prop(fluid, "simulation_scale", text="Meters") col = split.column() - col.label(text="Viscosity Presets:") - sub = col.row(align=True) - sub.menu("FLUID_MT_presets", text=bpy.types.FLUID_MT_presets.bl_label) - sub.operator("fluid.preset_add", text="", icon='ZOOMIN') - sub.operator("fluid.preset_add", text="", icon='ZOOMOUT').remove_active = True + FLUID_PT_presets.draw_menu(col, text="Viscosity Presets") sub = col.column(align=True) sub.prop(fluid, "viscosity_base", text="Base") @@ -258,15 +254,15 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel, Panel): class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel): - bl_label = "Fluid Boundary" + bl_label = "Boundary" + bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} @classmethod def poll(cls, context): md = context.fluid - rd = context.scene.render - return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES + return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES def draw(self, context): layout = self.layout @@ -289,15 +285,15 @@ class PHYSICS_PT_domain_boundary(PhysicButtonsPanel, Panel): class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel): - bl_label = "Fluid Particles" + bl_label = "Particles" + bl_parent_id = 'PHYSICS_PT_fluid' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} @classmethod def poll(cls, context): md = context.fluid - rd = context.scene.render - return md and md.settings and (md.settings.type == 'DOMAIN') and rd.engine in cls.COMPAT_ENGINES + return md and md.settings and (md.settings.type == 'DOMAIN') and context.engine in cls.COMPAT_ENGINES def draw(self, context): layout = self.layout @@ -310,7 +306,7 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel): classes = ( - FLUID_MT_presets, + FLUID_PT_presets, PHYSICS_PT_fluid, PHYSICS_PT_domain_gravity, PHYSICS_PT_domain_boundary, diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index 847df2e1fd7..d121b6a389d 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -29,46 +29,50 @@ class PHYSICS_PT_rigidbody_panel: class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel): bl_label = "Rigid Body" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): obj = context.object return (obj and obj.rigid_body and - (context.scene.render.engine in cls.COMPAT_ENGINES)) + (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object rbo = ob.rigid_body if rbo is not None: layout.prop(rbo, "type", text="Type") - row = layout.row() - if rbo.type == 'ACTIVE': - row.prop(rbo, "enabled", text="Dynamic") - row.prop(rbo, "kinematic", text="Animated") if rbo.type == 'ACTIVE': layout.prop(rbo, "mass") + col = layout.column() + if rbo.type == 'ACTIVE': + col.prop(rbo, "enabled", text="Dynamic") + col.prop(rbo, "kinematic", text="Animated") + class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): - bl_label = "Rigid Body Collisions" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_label = "Collisions" + bl_parent_id = 'PHYSICS_PT_rigid_body' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): obj = context.object return (obj and obj.rigid_body and - (context.scene.render.engine in cls.COMPAT_ENGINES)) + (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): layout = self.layout ob = context.object rbo = ob.rigid_body + layout.use_property_split = True layout.prop(rbo, "collision_shape", text="Shape") @@ -78,15 +82,52 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): if rbo.collision_shape == 'MESH' and rbo.mesh_source == 'DEFORM': layout.prop(rbo, "use_deform", text="Deforming") - split = layout.split() - col = split.column() - col.label(text="Surface Response:") +class PHYSICS_PT_rigid_body_collisions_surface(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Surface Response" + bl_parent_id = 'PHYSICS_PT_rigid_body_collisions' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + (context.engine in cls.COMPAT_ENGINES)) + + def draw(self, context): + layout = self.layout + + ob = context.object + rbo = ob.rigid_body + layout.use_property_split = True + + col = layout.column() col.prop(rbo, "friction") col.prop(rbo, "restitution", text="Bounciness") - col = split.column() - col.label(text="Sensitivity:") + +class PHYSICS_PT_rigid_body_collisions_sensitivity(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Sensitivity" + bl_parent_id = 'PHYSICS_PT_rigid_body_collisions' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + (context.engine in cls.COMPAT_ENGINES)) + + def draw(self, context): + layout = self.layout + + ob = context.object + rbo = ob.rigid_body + layout.use_property_split = True + + col = layout.column() + if rbo.collision_shape in {'MESH', 'CONE'}: col.prop(rbo, "collision_margin", text="Margin") else: @@ -95,23 +136,44 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): sub.active = rbo.use_margin sub.prop(rbo, "collision_margin", text="Margin") - layout.prop(rbo, "collision_groups") + +class PHYSICS_PT_rigid_body_collisions_collections(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Collision Collections" + bl_parent_id = 'PHYSICS_PT_rigid_body_collisions' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + (context.engine in cls.COMPAT_ENGINES)) + + def draw(self, context): + layout = self.layout + + ob = context.object + rbo = ob.rigid_body + + layout.prop(rbo, "collision_groups", text="") class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): - bl_label = "Rigid Body Dynamics" - bl_default_closed = True - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_label = "Dynamics" + bl_parent_id = 'PHYSICS_PT_rigid_body' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): obj = context.object return (obj and obj.rigid_body and obj.rigid_body.type == 'ACTIVE' and - (context.scene.render.engine in cls.COMPAT_ENGINES)) + (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): layout = self.layout + layout.use_property_split = True ob = context.object rbo = ob.rigid_body @@ -120,28 +182,53 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): # col.label(text="Activation:") # XXX: settings such as activate on collison/etc. - split = layout.split() + col = layout.column() + col.prop(rbo, "linear_damping", text="Translation Damping") + col.prop(rbo, "angular_damping", text="Rotation Damping") - col = split.column() - col.label(text="Deactivation:") - col.prop(rbo, "use_deactivation") - sub = col.column() - sub.active = rbo.use_deactivation - sub.prop(rbo, "use_start_deactivated") - sub.prop(rbo, "deactivate_linear_velocity", text="Linear Vel") - sub.prop(rbo, "deactivate_angular_velocity", text="Angular Vel") - # TODO: other params such as time? - col = split.column() - col.label(text="Damping:") - col.prop(rbo, "linear_damping", text="Translation") - col.prop(rbo, "angular_damping", text="Rotation") +class PHYSICS_PT_rigid_body_dynamics_deactivation(PHYSICS_PT_rigidbody_panel, Panel): + bl_label = "Deactivation" + bl_parent_id = 'PHYSICS_PT_rigid_body_dynamics' + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.rigid_body and + obj.rigid_body.type == 'ACTIVE' and + (context.engine in cls.COMPAT_ENGINES)) + + def draw_header(self, context): + ob = context.object + rbo = ob.rigid_body + self.layout.prop(rbo, "use_deactivation", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + ob = context.object + rbo = ob.rigid_body + + layout.active = rbo.use_deactivation + + col = layout.column() + col.prop(rbo, "use_start_deactivated") + col.prop(rbo, "deactivate_linear_velocity", text="Linear Velocity") + col.prop(rbo, "deactivate_angular_velocity", text="Angular Velocity") + # TODO: other params such as time? classes = ( PHYSICS_PT_rigid_body, PHYSICS_PT_rigid_body_collisions, + PHYSICS_PT_rigid_body_collisions_surface, + PHYSICS_PT_rigid_body_collisions_sensitivity, + PHYSICS_PT_rigid_body_collisions_collections, PHYSICS_PT_rigid_body_dynamics, + PHYSICS_PT_rigid_body_dynamics_deactivation, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py index 8f6b5b5d8b2..5e67caadc90 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py @@ -29,13 +29,12 @@ class PHYSICS_PT_rigidbody_constraint_panel: class PHYSICS_PT_rigid_body_constraint(PHYSICS_PT_rigidbody_constraint_panel, Panel): bl_label = "Rigid Body Constraint" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return (ob and ob.rigid_body_constraint and rd.engine in cls.COMPAT_ENGINES) + return (ob and ob.rigid_body_constraint and context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py index 9489fb71e15..0a4f1c71126 100644 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py @@ -34,13 +34,12 @@ class PhysicButtonsPanel: @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return (ob and ob.type == 'MESH') and (rd.engine in cls.COMPAT_ENGINES) and (context.smoke) + return (ob and ob.type == 'MESH') and (context.engine in cls.COMPAT_ENGINES) and (context.smoke) class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel): bl_label = "Smoke" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -136,9 +135,10 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel): class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel): - bl_label = "Smoke Flow Advanced" + bl_label = "Advanced" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -160,7 +160,7 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel): sub.label(text="Mapping:") sub.prop(flow, "texture_map_type", expand=False, text="") if flow.texture_map_type == 'UV': - sub.prop_search(flow, "uv_layer", ob.data, "uv_textures", text="") + sub.prop_search(flow, "uv_layer", ob.data, "uv_layers", text="") if flow.texture_map_type == 'AUTO': sub.prop(flow, "texture_size") sub.prop(flow, "texture_offset") @@ -171,9 +171,10 @@ class PHYSICS_PT_smoke_flow_advanced(PhysicButtonsPanel, Panel): class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel): - bl_label = "Smoke Flames" + bl_label = "Flames" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -201,9 +202,10 @@ class PHYSICS_PT_smoke_fire(PhysicButtonsPanel, Panel): class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel): - bl_label = "Smoke Adaptive Domain" + bl_label = "Adaptive Domain" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -235,15 +237,15 @@ class PHYSICS_PT_smoke_adaptive_domain(PhysicButtonsPanel, Panel): class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel): - bl_label = "Smoke High Resolution" + bl_label = "High Resolution" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.smoke - rd = context.scene.render - return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES) + return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES) def draw_header(self, context): md = context.smoke.domain_settings @@ -275,15 +277,15 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, Panel): class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel): - bl_label = "Smoke Groups" + bl_label = "Groups" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.smoke - rd = context.scene.render - return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES) + return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout @@ -304,15 +306,15 @@ class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, Panel): class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel): - bl_label = "Smoke Cache" + bl_label = "Cache" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.smoke - rd = context.scene.render - return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES) + return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout @@ -341,30 +343,30 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel): class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, Panel): - bl_label = "Smoke Field Weights" + bl_label = "Field Weights" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): md = context.smoke - rd = context.scene.render - return md and (md.smoke_type == 'DOMAIN') and (rd.engine in cls.COMPAT_ENGINES) + return md and (md.smoke_type == 'DOMAIN') and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): domain = context.smoke.domain_settings effector_weights_ui(self, context, domain.effector_weights, 'SMOKE') -class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel): - bl_label = "Smoke Display Settings" +class PHYSICS_PT_smoke_viewport_display(PhysicButtonsPanel, Panel): + bl_label = "Viewport Display" + bl_parent_id = 'PHYSICS_PT_smoke' bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): md = context.smoke - rd = context.scene.render - return md and (md.smoke_type == 'DOMAIN') and (not rd.use_game_engine) + return md and (md.smoke_type == 'DOMAIN') def draw(self, context): domain = context.smoke.domain_settings @@ -395,23 +397,53 @@ class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel): row.enabled = do_full_slicing or not do_axis_slicing row.prop(domain, "slice_per_voxel") - layout.separator() - layout.label(text="Debug:") - layout.prop(domain, "draw_velocity") - col = layout.column() - col.enabled = domain.draw_velocity - col.prop(domain, "vector_draw_type") - col.prop(domain, "vector_scale") - layout.separator() - layout.label(text="Color Mapping:") - layout.prop(domain, "use_color_ramp") +class PHYSICS_PT_smoke_viewport_display_color(PhysicButtonsPanel, Panel): + bl_label = "Color Mapping" + bl_parent_id = 'PHYSICS_PT_smoke_viewport_display' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + md = context.smoke + return md and (md.smoke_type == 'DOMAIN') + + def draw_header(self, context): + md = context.smoke.domain_settings + + self.layout.prop(md, "use_color_ramp", text="") + + def draw(self, context): + domain = context.smoke.domain_settings + layout = self.layout + col = layout.column() col.enabled = domain.use_color_ramp col.prop(domain, "coba_field") col.template_color_ramp(domain, "color_ramp", expand=True) +class PHYSICS_PT_smoke_viewport_display_debug(PhysicButtonsPanel, Panel): + bl_label = "Debug" + bl_parent_id = 'PHYSICS_PT_smoke_viewport_display' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + md = context.smoke + return md and (md.smoke_type == 'DOMAIN') + + def draw(self, context): + domain = context.smoke.domain_settings + layout = self.layout + + layout.prop(domain, "draw_velocity") + col = layout.column() + col.enabled = domain.draw_velocity + col.prop(domain, "vector_draw_type") + col.prop(domain, "vector_scale") + + classes = ( PHYSICS_PT_smoke, PHYSICS_PT_smoke_flow_advanced, @@ -421,7 +453,9 @@ classes = ( PHYSICS_PT_smoke_groups, PHYSICS_PT_smoke_cache, PHYSICS_PT_smoke_field_weights, - PHYSICS_PT_smoke_display_settings, + PHYSICS_PT_smoke_viewport_display, + PHYSICS_PT_smoke_viewport_display_color, + PHYSICS_PT_smoke_viewport_display_debug, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py index 8f193427441..77440bdc628 100644 --- a/release/scripts/startup/bl_ui/properties_physics_softbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py @@ -41,13 +41,12 @@ class PhysicButtonsPanel: @classmethod def poll(cls, context): ob = context.object - rd = context.scene.render - return ob and ob.type in COMPAT_OB_TYPES and rd.engine in cls.COMPAT_ENGINES and context.soft_body + return ob and ob.type in COMPAT_OB_TYPES and context.engine in cls.COMPAT_ENGINES and context.soft_body class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel): bl_label = "Soft Body" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -75,9 +74,10 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel, Panel): class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel): - bl_label = "Soft Body Cache" + bl_label = "Cache" + bl_parent_id = 'PHYSICS_PT_softbody' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): md = context.soft_body @@ -85,9 +85,10 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel, Panel): class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel): - bl_label = "Soft Body Goal" + bl_label = "Goal" + bl_parent_id = 'PHYSICS_PT_softbody' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): softbody = context.soft_body.settings @@ -125,9 +126,10 @@ class PHYSICS_PT_softbody_goal(PhysicButtonsPanel, Panel): class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel): - bl_label = "Soft Body Edges" + bl_label = "Edges" + bl_parent_id = 'PHYSICS_PT_softbody' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): softbody = context.soft_body.settings @@ -175,9 +177,10 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel, Panel): class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel): - bl_label = "Soft Body Self Collision" + bl_label = "Self Collision" + bl_parent_id = 'PHYSICS_PT_softbody' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): softbody = context.soft_body.settings @@ -204,9 +207,10 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel, Panel): class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel): - bl_label = "Soft Body Solver" + bl_label = "Solver" + bl_parent_id = 'PHYSICS_PT_softbody' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout @@ -237,9 +241,10 @@ class PHYSICS_PT_softbody_solver(PhysicButtonsPanel, Panel): class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, Panel): - bl_label = "Soft Body Field Weights" + bl_label = "Field Weights" + bl_parent_id = 'PHYSICS_PT_softbody' bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): md = context.soft_body diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index bd5d926d4cd..2b91eec67c4 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -19,21 +19,26 @@ # <pep8 compliant> import bpy -from bpy.types import Menu, Panel +from bpy.types import Menu, Panel, UIList +from bl_operators.presets import PresetMenu +from .space_view3d import ( + VIEW3D_PT_shading_lighting, + VIEW3D_PT_shading_color, + VIEW3D_PT_shading_options, +) -class RENDER_MT_presets(Menu): +class RENDER_PT_presets(PresetMenu): bl_label = "Render Presets" preset_subdir = "render" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "render.preset_add" -class RENDER_MT_ffmpeg_presets(Menu): +class RENDER_PT_ffmpeg_presets(PresetMenu): bl_label = "FFMPEG Presets" preset_subdir = "ffmpeg" preset_operator = "script.python_file_run" - draw = Menu.draw_preset class RENDER_MT_framerate_presets(Menu): @@ -51,39 +56,42 @@ class RenderButtonsPanel: @classmethod def poll(cls, context): - scene = context.scene - return scene and (scene.render.engine in cls.COMPAT_ENGINES) + return (context.engine in cls.COMPAT_ENGINES) + +class RENDER_PT_context(Panel): + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "render" + bl_options = {'HIDE_HEADER'} + bl_label = "" -class RENDER_PT_render(RenderButtonsPanel, Panel): - bl_label = "Render" - COMPAT_ENGINES = {'BLENDER_RENDER'} + @classmethod + def poll(cls, context): + return context.scene def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False - rd = context.scene.render - - row = layout.row(align=True) - row.operator("render.render", text="Render", icon='RENDER_STILL') - row.operator("render.render", text="Animation", icon='RENDER_ANIMATION').animation = True - row.operator("sound.mixdown", text="Audio", icon='PLAY_AUDIO') - - split = layout.split(percentage=0.33) + scene = context.scene + rd = scene.render - split.label(text="Display:") - row = split.row(align=True) - row.prop(rd, "display_mode", text="") - row.prop(rd, "use_lock_interface", icon_only=True) + if rd.has_multiple_engines: + layout.prop(rd, "engine", text="Render Engine") class RENDER_PT_dimensions(RenderButtonsPanel, Panel): bl_label = "Dimensions" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _frame_rate_args_prev = None _preset_class = None + def draw_header_preset(self, context): + RENDER_PT_presets.draw_panel_header(self.layout) + @staticmethod def _draw_framerate_label(*args): # avoids re-creating text string each draw @@ -112,7 +120,7 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel): return args @staticmethod - def draw_framerate(sub, rd): + def draw_framerate(layout, sub, rd): if RENDER_PT_dimensions._preset_class is None: RENDER_PT_dimensions._preset_class = bpy.types.RENDER_MT_framerate_presets @@ -122,273 +130,166 @@ class RENDER_PT_dimensions(RenderButtonsPanel, Panel): sub.menu("RENDER_MT_framerate_presets", text=fps_label_text) if show_framerate: - sub.prop(rd, "fps") - sub.prop(rd, "fps_base", text="/") + col = layout.column(align=True) + col.prop(rd, "fps") + col.prop(rd, "fps_base", text="Base") def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. scene = context.scene rd = scene.render - row = layout.row(align=True) - row.menu("RENDER_MT_presets", text=bpy.types.RENDER_MT_presets.bl_label) - row.operator("render.preset_add", text="", icon='ZOOMIN') - row.operator("render.preset_add", text="", icon='ZOOMOUT').remove_active = True + col = layout.column(align=True) + col.prop(rd, "resolution_x", text="Resolution X") + col.prop(rd, "resolution_y", text="Y") + col.prop(rd, "resolution_percentage", text="%") - split = layout.split() + col = layout.column(align=True) + col.prop(rd, "pixel_aspect_x", text="Aspect X") + col.prop(rd, "pixel_aspect_y", text="Y") - col = split.column() + col = layout.column(align=True) + col.prop(rd, "use_border", text="Border") sub = col.column(align=True) - sub.label(text="Resolution:") - sub.prop(rd, "resolution_x", text="X") - sub.prop(rd, "resolution_y", text="Y") - sub.prop(rd, "resolution_percentage", text="") - - sub.label(text="Aspect Ratio:") - sub.prop(rd, "pixel_aspect_x", text="X") - sub.prop(rd, "pixel_aspect_y", text="Y") - - row = col.row() - row.prop(rd, "use_border", text="Border") - sub = row.row() sub.active = rd.use_border sub.prop(rd, "use_crop_to_border", text="Crop") - col = split.column() - sub = col.column(align=True) - sub.label(text="Frame Range:") - sub.prop(scene, "frame_start") - sub.prop(scene, "frame_end") - sub.prop(scene, "frame_step") - - sub.label(text="Frame Rate:") - - self.draw_framerate(sub, rd) + col = layout.column(align=True) + col.prop(scene, "frame_start", text="Frame Start") + col.prop(scene, "frame_end", text="End") + col.prop(scene, "frame_step", text="Step") - subrow = sub.row(align=True) - subrow.label(text="Time Remapping:") - subrow = sub.row(align=True) - subrow.prop(rd, "frame_map_old", text="Old") - subrow.prop(rd, "frame_map_new", text="New") + col = layout.split() + col.alignment = 'RIGHT' + col.label(text="Frame Rate") + self.draw_framerate(layout, col, rd) -class RENDER_PT_antialiasing(RenderButtonsPanel, Panel): - bl_label = "Anti-Aliasing" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw_header(self, context): - rd = context.scene.render - - self.layout.prop(rd, "use_antialiasing", text="") - - def draw(self, context): - layout = self.layout - - rd = context.scene.render - layout.active = rd.use_antialiasing - - split = layout.split() - - col = split.column() - col.row().prop(rd, "antialiasing_samples", expand=True) - sub = col.row() - sub.prop(rd, "use_full_sample") - - col = split.column() - col.prop(rd, "pixel_filter_type", text="") - col.prop(rd, "filter_size", text="Size") - - -class RENDER_PT_motion_blur(RenderButtonsPanel, Panel): - bl_label = "Sampled Motion Blur" +class RENDER_PT_frame_remapping(RenderButtonsPanel, Panel): + bl_label = "Time Remapping" + bl_parent_id = "RENDER_PT_dimensions" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @classmethod - def poll(cls, context): - rd = context.scene.render - return not rd.use_full_sample and (rd.engine in cls.COMPAT_ENGINES) - - def draw_header(self, context): - rd = context.scene.render - - self.layout.prop(rd, "use_motion_blur", text="") + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. rd = context.scene.render - layout.active = rd.use_motion_blur - row = layout.row() - row.prop(rd, "motion_blur_samples") - row.prop(rd, "motion_blur_shutter") + col = layout.column(align=True) + col.prop(rd, "frame_map_old", text="Old") + col.prop(rd, "frame_map_new", text="New") -class RENDER_PT_shading(RenderButtonsPanel, Panel): - bl_label = "Shading" +class RENDER_PT_post_processing(RenderButtonsPanel, Panel): + bl_label = "Post Processing" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True rd = context.scene.render - split = layout.split() - - col = split.column() - col.prop(rd, "use_textures", text="Textures") - col.prop(rd, "use_shadows", text="Shadows") - col.prop(rd, "use_sss", text="Subsurface Scattering") - col.prop(rd, "use_envmaps", text="Environment Map") + col = layout.column(align=True) + col.prop(rd, "use_compositing") + col.prop(rd, "use_sequencer") - col = split.column() - col.prop(rd, "use_raytrace", text="Ray Tracing") - col.prop(rd, "alpha_mode", text="Alpha") - col.prop(rd, "use_world_space_shading", text="World Space Shading") + col.prop(rd, "dither_intensity", text="Dither", slider=True) -class RENDER_PT_performance(RenderButtonsPanel, Panel): - bl_label = "Performance" +class RENDER_PT_stamp(RenderButtonsPanel, Panel): + bl_label = "Metadata" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. rd = context.scene.render split = layout.split() col = split.column(align=True) - col.label(text="Threads:") - col.row(align=True).prop(rd, "threads_mode", expand=True) - sub = col.column(align=True) - sub.enabled = rd.threads_mode == 'FIXED' - sub.prop(rd, "threads") - - col.label(text="Tile Size:") - col.prop(rd, "tile_x", text="X") - col.prop(rd, "tile_y", text="Y") + col.prop(rd, "use_stamp_date", text="Date") + col.prop(rd, "use_stamp_time", text="Time") col.separator() - col.prop(rd, "preview_start_resolution") - col.prop(rd, "preview_pixel_size", text="") - col = split.column() - col.label(text="Memory:") - sub = col.column() - sub.enabled = not rd.use_full_sample - sub.prop(rd, "use_save_buffers") - sub = col.column() - sub.active = rd.use_compositing - sub.prop(rd, "use_free_image_textures") - sub = col.column() - sub.active = rd.use_raytrace - sub.label(text="Acceleration Structure:") - sub.prop(rd, "raytrace_method", text="") - if rd.raytrace_method == 'OCTREE': - sub.prop(rd, "octree_resolution", text="Resolution") - else: - sub.prop(rd, "use_instances", text="Instances") - sub.prop(rd, "use_local_coords", text="Local Coordinates") + col.prop(rd, "use_stamp_render_time", text="Render Time") + col.prop(rd, "use_stamp_frame", text="Frame") + col.prop(rd, "use_stamp_frame_range", text="Frame Range") + col.prop(rd, "use_stamp_memory", text="Memory") + col = split.column(align=True) + col.prop(rd, "use_stamp_camera", text="Camera") + col.prop(rd, "use_stamp_lens", text="Lens") -class RENDER_PT_post_processing(RenderButtonsPanel, Panel): - bl_label = "Post Processing" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + col.separator() - def draw(self, context): - layout = self.layout + col.prop(rd, "use_stamp_scene", text="Scene") + col.prop(rd, "use_stamp_marker", text="Marker") - rd = context.scene.render + col.separator() - split = layout.split() + col.prop(rd, "use_stamp_filename", text="Filename") - col = split.column() - col.prop(rd, "use_compositing") - col.prop(rd, "use_sequencer") + col.separator() - split.prop(rd, "dither_intensity", text="Dither", slider=True) + col.prop(rd, "use_stamp_sequencer_strip", text="Strip Name") - layout.separator() + if rd.use_sequencer: + col.prop(rd, "use_stamp_strip_meta", text="Use Strip Metadata") - split = layout.split() + row = layout.split(percentage=0.3) + row.prop(rd, "use_stamp_note", text="Note") + sub = row.row() + sub.active = rd.use_stamp_note + sub.prop(rd, "stamp_note_text", text="") - col = split.column() - col.prop(rd, "use_fields", text="Fields") - sub = col.column() - sub.active = rd.use_fields - sub.row().prop(rd, "field_order", expand=True) - sub.prop(rd, "use_fields_still", text="Still") - col = split.column() - col.prop(rd, "use_edge_enhance") - sub = col.column() - sub.active = rd.use_edge_enhance - sub.prop(rd, "edge_threshold", text="Threshold", slider=True) - sub.prop(rd, "edge_color", text="") +class RENDER_PT_stamp_burn(RenderButtonsPanel, Panel): + bl_label = "Burn Into Image" + bl_parent_id = "RENDER_PT_stamp" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + def draw_header(self, context): + rd = context.scene.render -class RENDER_PT_stamp(RenderButtonsPanel, Panel): - bl_label = "Metadata" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + self.layout.prop(rd, "use_stamp", text="") def draw(self, context): layout = self.layout rd = context.scene.render - layout.prop(rd, "use_stamp") + layout.use_property_split = True + col = layout.column() col.active = rd.use_stamp - row = col.row() - row.prop(rd, "stamp_font_size", text="Font Size") - row.prop(rd, "use_stamp_labels", text="Draw Labels") - - row = col.row() - row.column().prop(rd, "stamp_foreground", slider=True) - row.column().prop(rd, "stamp_background", slider=True) - - layout.label("Enabled Metadata") - split = layout.split() - - col = split.column() - col.prop(rd, "use_stamp_time", text="Time") - col.prop(rd, "use_stamp_date", text="Date") - col.prop(rd, "use_stamp_render_time", text="RenderTime") - col.prop(rd, "use_stamp_frame", text="Frame") - col.prop(rd, "use_stamp_scene", text="Scene") - col.prop(rd, "use_stamp_memory", text="Memory") - - col = split.column() - col.prop(rd, "use_stamp_camera", text="Camera") - col.prop(rd, "use_stamp_lens", text="Lens") - col.prop(rd, "use_stamp_filename", text="Filename") - col.prop(rd, "use_stamp_frame_range", text="Frame range") - col.prop(rd, "use_stamp_marker", text="Marker") - col.prop(rd, "use_stamp_sequencer_strip", text="Seq. Strip") - - row = layout.split(percentage=0.2) - row.prop(rd, "use_stamp_note", text="Note") - sub = row.row() - sub.active = rd.use_stamp_note - sub.prop(rd, "stamp_note_text", text="") - if rd.use_sequencer: - layout.label("Sequencer:") - layout.prop(rd, "use_stamp_strip_meta") + col.prop(rd, "stamp_font_size", text="Font Size") + col.prop(rd, "use_stamp_labels", text="Draw Labels") + col.column().prop(rd, "stamp_foreground", slider=True) + col.column().prop(rd, "stamp_background", slider=True) class RENDER_PT_output(RenderButtonsPanel, Panel): bl_label = "Output" - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = False + layout.use_property_decorate = False # No animation. rd = context.scene.render image_settings = rd.image_settings @@ -396,17 +297,17 @@ class RENDER_PT_output(RenderButtonsPanel, Panel): layout.prop(rd, "filepath", text="") - split = layout.split() - - col = split.column() - col.active = not rd.is_movie_format - col.prop(rd, "use_overwrite") - col.prop(rd, "use_placeholder") + layout.use_property_split = True - col = split.column() + col = layout.column(align=True) + sub = col.column(align=True) + sub.active = not rd.is_movie_format + sub.prop(rd, "use_overwrite") + sub.prop(rd, "use_placeholder") col.prop(rd, "use_file_extension") col.prop(rd, "use_render_cache") + layout.use_property_split = False layout.template_image_settings(image_settings, color_management=False) if rd.use_multiview: layout.template_image_views(image_settings) @@ -415,7 +316,10 @@ class RENDER_PT_output(RenderButtonsPanel, Panel): class RENDER_PT_encoding(RenderButtonsPanel, Panel): bl_label = "Encoding" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header_preset(self, context): + RENDER_PT_ffmpeg_presets.draw_panel_header(self.layout) @classmethod def poll(cls, context): @@ -428,8 +332,6 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel): rd = context.scene.render ffmpeg = rd.ffmpeg - layout.menu("RENDER_MT_ffmpeg_presets", text="Presets") - split = layout.split() split.prop(rd.ffmpeg, "format") split.prop(ffmpeg, "use_autosplit") @@ -494,92 +396,508 @@ class RENDER_PT_encoding(RenderButtonsPanel, Panel): col.prop(ffmpeg, "packetsize", text="Packet Size") -class RENDER_PT_bake(RenderButtonsPanel, Panel): - bl_label = "Bake" +class RENDER_UL_renderviews(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + view = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + if view.name in {"left", "right"}: + layout.label(view.name, icon_value=icon + (not view.use)) + else: + layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False) + layout.prop(view, "use", text="", index=index) + + elif self.layout_type == 'GRID': + layout.alignment = 'CENTER' + layout.label("", icon_value=icon + (not view.use)) + + +class RENDER_PT_stereoscopy(RenderButtonsPanel, Panel): + bl_label = "Stereoscopy" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + + def draw_header(self, context): + rd = context.scene.render + self.layout.prop(rd, "use_multiview", text="") def draw(self, context): layout = self.layout - rd = context.scene.render + scene = context.scene + rd = scene.render + rv = rd.views.active - layout.operator("object.bake_image", icon='RENDER_STILL') + layout.active = rd.use_multiview + basic_stereo = rd.views_format == 'STEREO_3D' - layout.prop(rd, "bake_type") + row = layout.row() + row.prop(rd, "views_format", expand=True) - multires_bake = False - if rd.bake_type in ['NORMALS', 'DISPLACEMENT', 'DERIVATIVE', 'AO']: - layout.prop(rd, "use_bake_multires") - multires_bake = rd.use_bake_multires + if basic_stereo: + row = layout.row() + row.template_list("RENDER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2) - if not multires_bake: - if rd.bake_type == 'NORMALS': - layout.prop(rd, "bake_normal_space") - elif rd.bake_type in {'DISPLACEMENT', 'AO'}: - layout.prop(rd, "use_bake_normalize") + row = layout.row() + row.label(text="File Suffix:") + row.prop(rv, "file_suffix", text="") - # col.prop(rd, "bake_aa_mode") - # col.prop(rd, "use_bake_antialiasing") + else: + row = layout.row() + row.template_list("RENDER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2) - layout.separator() + col = row.column(align=True) + col.operator("scene.render_view_add", icon='ZOOMIN', text="") + col.operator("scene.render_view_remove", icon='ZOOMOUT', text="") - split = layout.split() + row = layout.row() + row.label(text="Camera Suffix:") + row.prop(rv, "camera_suffix", text="") - col = split.column() - col.prop(rd, "use_bake_to_vertex_color") - sub = col.column() - sub.active = not rd.use_bake_to_vertex_color - sub.prop(rd, "use_bake_clear") - sub.prop(rd, "bake_margin") - sub.prop(rd, "bake_quad_split", text="Split") - col = split.column() - col.prop(rd, "use_bake_selected_to_active") - sub = col.column() - sub.active = rd.use_bake_selected_to_active - sub.prop(rd, "bake_distance") - sub.prop(rd, "bake_bias") +class RENDER_PT_eevee_ambient_occlusion(RenderButtonsPanel, Panel): + bl_label = "Ambient Occlusion" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_gtao", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene + props = scene.eevee + + layout.active = props.use_gtao + col = layout.column() + col.prop(props, "use_gtao_bent_normals") + col.prop(props, "use_gtao_bounce") + col.prop(props, "gtao_distance") + col.prop(props, "gtao_factor") + col.prop(props, "gtao_quality") + + +class RENDER_PT_eevee_motion_blur(RenderButtonsPanel, Panel): + bl_label = "Motion Blur" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_motion_blur", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene + props = scene.eevee + + layout.active = props.use_motion_blur + col = layout.column() + col.prop(props, "motion_blur_samples") + col.prop(props, "motion_blur_shutter") + + +class RENDER_PT_eevee_depth_of_field(RenderButtonsPanel, Panel): + bl_label = "Depth of Field" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_dof", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene + props = scene.eevee + + layout.active = props.use_dof + col = layout.column() + col.prop(props, "bokeh_max_size") + col.prop(props, "bokeh_threshold") + + +class RENDER_PT_eevee_bloom(RenderButtonsPanel, Panel): + bl_label = "Bloom" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_bloom", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + props = scene.eevee + + layout.active = props.use_bloom + col = layout.column() + col.prop(props, "bloom_threshold") + col.prop(props, "bloom_knee") + col.prop(props, "bloom_radius") + col.prop(props, "bloom_color") + col.prop(props, "bloom_intensity") + col.prop(props, "bloom_clamp") + + +class RENDER_PT_eevee_volumetric(RenderButtonsPanel, Panel): + bl_label = "Volumetric" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_volumetric", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + props = scene.eevee + + layout.active = props.use_volumetric + col = layout.column() + sub = col.column(align=True) + sub.prop(props, "volumetric_start") + sub.prop(props, "volumetric_end") + col.prop(props, "volumetric_tile_size") + col.separator() + col.prop(props, "volumetric_samples") + sub.prop(props, "volumetric_sample_distribution") + col.separator() + col.prop(props, "use_volumetric_lights") + + sub = col.column() + sub.active = props.use_volumetric_lights + sub.prop(props, "volumetric_light_clamp", text="Light Clamping") + col.separator() + col.prop(props, "use_volumetric_shadows") + sub = col.column() + sub.active = props.use_volumetric_shadows + sub.prop(props, "volumetric_shadow_samples", text="Shadow Samples") + + +class RENDER_PT_eevee_subsurface_scattering(RenderButtonsPanel, Panel): + bl_label = "Subsurface Scattering" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_sss", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + props = scene.eevee + + layout.active = props.use_sss + + col = layout.column() + col.prop(props, "sss_samples") + col.prop(props, "sss_jitter_threshold") + col.prop(props, "use_sss_separate_albedo") + + +class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel): + bl_label = "Screen Space Reflections" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + scene = context.scene + props = scene.eevee + self.layout.prop(props, "use_ssr", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + props = scene.eevee + + col = layout.column() + col.active = props.use_ssr + col.prop(props, "use_ssr_refraction", text="Refraction") + col.prop(props, "use_ssr_halfres") + col.prop(props, "ssr_quality") + col.prop(props, "ssr_max_roughness") + col.prop(props, "ssr_thickness") + col.prop(props, "ssr_border_fade") + col.prop(props, "ssr_firefly_fac") + + +class RENDER_PT_eevee_shadows(RenderButtonsPanel, Panel): + bl_label = "Shadows" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + props = scene.eevee + + col = layout.column() + col.prop(props, "shadow_method") + col.prop(props, "shadow_cube_size", text="Cube Size") + col.prop(props, "shadow_cascade_size", text="Cascade Size") + col.prop(props, "use_shadow_high_bitdepth") + + +class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel): + bl_label = "Sampling" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + scene = context.scene + props = scene.eevee + + col = layout.column() + col.prop(props, "taa_samples") + col.prop(props, "taa_render_samples") + col.prop(props, "use_taa_reprojection") + + +class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel): + bl_label = "Indirect Lighting" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + scene = context.scene + props = scene.eevee + + col = layout.column() + col.operator("scene.light_cache_bake", text="Bake Indirect Lighting", icon='RENDER_STILL') + col.operator("scene.light_cache_bake", text="Bake Cubemap Only", icon='LIGHTPROBE_CUBEMAP').subset = "CUBEMAPS" + col.operator("scene.light_cache_free", text="Free Lighting Cache") + + cache_info = scene.eevee.gi_cache_info + if cache_info: + col.label(text=cache_info) + + col.prop(props, "gi_auto_bake") + + col.prop(props, "gi_diffuse_bounces") + col.prop(props, "gi_cubemap_resolution") + col.prop(props, "gi_visibility_resolution", text="Diffuse Occlusion") + + layout.use_property_split = False + row = layout.split(percentage=0.5) + row.alignment = 'RIGHT' + row.label("Cubemap Display") + + sub = row.row(align=True) + sub.prop(props, "gi_cubemap_draw_size", text="Size") + if props.gi_show_cubemaps: + sub.prop(props, "gi_show_cubemaps", text="", toggle=True, icon='HIDE_OFF') else: - split = layout.split() + sub.prop(props, "gi_show_cubemaps", text="", toggle=True, icon='HIDE_ON') - col = split.column() - col.prop(rd, "use_bake_clear") - col.prop(rd, "bake_margin") + row = layout.split(percentage=0.5) + row.alignment = 'RIGHT' + row.label("Irradiance Display") - if rd.bake_type == 'DISPLACEMENT': - col = split.column() - col.prop(rd, "use_bake_lores_mesh") + sub = row.row(align=True) + sub.prop(props, "gi_irradiance_draw_size", text="Size") + if props.gi_show_irradiance: + sub.prop(props, "gi_show_irradiance", text="", toggle=True, icon='HIDE_OFF') + else: + sub.prop(props, "gi_show_irradiance", text="", toggle=True, icon='HIDE_ON') - if rd.bake_type == 'AO': - col = split.column() - col.prop(rd, "bake_bias") - col.prop(rd, "bake_samples") - if rd.bake_type == 'DERIVATIVE': - row = layout.row() - row.prop(rd, "use_bake_user_scale", text="") +class RENDER_PT_eevee_film(RenderButtonsPanel, Panel): + bl_label = "Film" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + rd = scene.render + + col = layout.column() + col.prop(rd, "filter_size") + col.prop(rd, "alpha_mode", text="Alpha") + + +class RENDER_PT_eevee_hair(RenderButtonsPanel, Panel): + bl_label = "Hair" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + scene = context.scene + rd = scene.render + + row = layout.row() + row.prop(rd, "hair_type", expand=True) + + layout.use_property_split = True + layout.prop(rd, "hair_subdiv") + + +class RENDER_PT_opengl_film(RenderButtonsPanel, Panel): + bl_label = "Film" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + rd = context.scene.render + + layout.prop(rd, "use_antialiasing") + + layout.prop(rd, "antialiasing_samples") + layout.prop(rd, "alpha_mode") - sub = row.column() - sub.active = rd.use_bake_user_scale - sub.prop(rd, "bake_user_scale", text="User Scale") + +class RENDER_PT_opengl_lighting(RenderButtonsPanel, Panel): + bl_label = "Lighting" + COMPAT_ENGINES = {'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + VIEW3D_PT_shading_lighting.draw(self, context) + + +class RENDER_PT_opengl_color(RenderButtonsPanel, Panel): + bl_label = "Color" + COMPAT_ENGINES = {'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + VIEW3D_PT_shading_color.draw(self, context) + + +class RENDER_PT_opengl_options(RenderButtonsPanel, Panel): + bl_label = "Options" + COMPAT_ENGINES = {'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + VIEW3D_PT_shading_options.draw(self, context) classes = ( - RENDER_MT_presets, - RENDER_MT_ffmpeg_presets, + RENDER_PT_presets, + RENDER_PT_ffmpeg_presets, RENDER_MT_framerate_presets, - RENDER_PT_render, + RENDER_PT_context, RENDER_PT_dimensions, - RENDER_PT_antialiasing, - RENDER_PT_motion_blur, - RENDER_PT_shading, - RENDER_PT_performance, + RENDER_PT_frame_remapping, RENDER_PT_post_processing, - RENDER_PT_stamp, RENDER_PT_output, RENDER_PT_encoding, - RENDER_PT_bake, + RENDER_PT_stamp, + RENDER_PT_stamp_burn, + RENDER_UL_renderviews, + RENDER_PT_stereoscopy, + RENDER_PT_eevee_hair, + RENDER_PT_eevee_sampling, + RENDER_PT_eevee_film, + RENDER_PT_eevee_shadows, + RENDER_PT_eevee_indirect_lighting, + RENDER_PT_eevee_subsurface_scattering, + RENDER_PT_eevee_screen_space_reflections, + RENDER_PT_eevee_ambient_occlusion, + RENDER_PT_eevee_volumetric, + RENDER_PT_eevee_motion_blur, + RENDER_PT_eevee_depth_of_field, + RENDER_PT_eevee_bloom, + RENDER_PT_opengl_film, + RENDER_PT_opengl_lighting, + RENDER_PT_opengl_color, + RENDER_PT_opengl_options, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py deleted file mode 100644 index 084bc387822..00000000000 --- a/release/scripts/startup/bl_ui/properties_render_layer.py +++ /dev/null @@ -1,242 +0,0 @@ -# ##### 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> -import bpy -from bpy.types import Panel, UIList - - -class RenderLayerButtonsPanel: - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "render_layer" - # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here - - @classmethod - def poll(cls, context): - scene = context.scene - return scene and (scene.render.engine in cls.COMPAT_ENGINES) - - -class RENDERLAYER_UL_renderlayers(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.SceneRenderLayer) - layer = item - if self.layout_type in {'DEFAULT', 'COMPACT'}: - layout.prop(layer, "name", text="", icon_value=icon, emboss=False) - layout.prop(layer, "use", text="", index=index) - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label("", icon_value=icon) - - -class RENDERLAYER_PT_layers(RenderLayerButtonsPanel, Panel): - bl_label = "Layer List" - bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render - - if rd.engine == 'BLENDER_GAME': - layout.label("Not available in the Game Engine") - return - - row = layout.row() - col = row.column() - col.template_list("RENDERLAYER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2) - - col = row.column() - sub = col.column(align=True) - sub.operator("scene.render_layer_add", icon='ZOOMIN', text="") - sub.operator("scene.render_layer_remove", icon='ZOOMOUT', text="") - col.prop(rd, "use_single_layer", icon_only=True) - - -class RENDERLAYER_PT_layer_options(RenderLayerButtonsPanel, Panel): - bl_label = "Layer" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render - rl = rd.layers.active - - split = layout.split() - - col = split.column() - col.prop(scene, "layers", text="Scene") - col.label(text="") - col.prop(rl, "light_override", text="Lights") - col.prop(rl, "material_override", text="Material") - - col = split.column() - col.prop(rl, "layers", text="Layer") - col.prop(rl, "layers_zmask", text="Mask Layer") - - layout.separator() - layout.label(text="Include:") - - split = layout.split() - - col = split.column() - col.prop(rl, "use_zmask") - row = col.row() - row.prop(rl, "invert_zmask", text="Negate") - row.active = rl.use_zmask - col.prop(rl, "use_all_z") - - col = split.column() - col.prop(rl, "use_solid") - col.prop(rl, "use_halo") - col.prop(rl, "use_ztransp") - - col = split.column() - col.prop(rl, "use_sky") - col.prop(rl, "use_edge_enhance") - col.prop(rl, "use_strand") - if bpy.app.build_options.freestyle: - row = col.row() - row.prop(rl, "use_freestyle") - row.active = rd.use_freestyle - - -class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel): - bl_label = "Passes" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} - - @staticmethod - def draw_pass_type_buttons(box, rl, pass_type): - # property names - use_pass_type = "use_pass_" + pass_type - exclude_pass_type = "exclude_" + pass_type - # draw pass type buttons - row = box.row() - row.prop(rl, use_pass_type) - row.prop(rl, exclude_pass_type, text="") - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render - rl = rd.layers.active - - split = layout.split() - - col = split.column() - col.prop(rl, "use_pass_combined") - col.prop(rl, "use_pass_z") - col.prop(rl, "use_pass_vector") - col.prop(rl, "use_pass_normal") - col.prop(rl, "use_pass_uv") - col.prop(rl, "use_pass_mist") - col.prop(rl, "use_pass_object_index") - col.prop(rl, "use_pass_material_index") - col.prop(rl, "use_pass_color") - - col = split.column() - col.prop(rl, "use_pass_diffuse") - self.draw_pass_type_buttons(col, rl, "specular") - self.draw_pass_type_buttons(col, rl, "shadow") - self.draw_pass_type_buttons(col, rl, "emit") - self.draw_pass_type_buttons(col, rl, "ambient_occlusion") - self.draw_pass_type_buttons(col, rl, "environment") - self.draw_pass_type_buttons(col, rl, "indirect") - self.draw_pass_type_buttons(col, rl, "reflection") - self.draw_pass_type_buttons(col, rl, "refraction") - - -class RENDERLAYER_UL_renderviews(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.SceneRenderView) - view = item - if self.layout_type in {'DEFAULT', 'COMPACT'}: - if view.name in {'left', 'right'}: - layout.label(view.name, icon_value=icon + (not view.use)) - else: - layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False) - layout.prop(view, "use", text="", index=index) - - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label("", icon_value=icon + (not view.use)) - - -class RENDERLAYER_PT_views(RenderLayerButtonsPanel, Panel): - bl_label = "Views" - COMPAT_ENGINES = {'BLENDER_RENDER'} - bl_options = {'DEFAULT_CLOSED'} - - def draw_header(self, context): - rd = context.scene.render - self.layout.prop(rd, "use_multiview", text="") - - def draw(self, context): - layout = self.layout - - scene = context.scene - rd = scene.render - rv = rd.views.active - - layout.active = rd.use_multiview - basic_stereo = rd.views_format == 'STEREO_3D' - - row = layout.row() - row.prop(rd, "views_format", expand=True) - - if basic_stereo: - row = layout.row() - row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2) - - row = layout.row() - row.label(text="File Suffix:") - row.prop(rv, "file_suffix", text="") - - else: - row = layout.row() - row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2) - - col = row.column(align=True) - col.operator("scene.render_view_add", icon='ZOOMIN', text="") - col.operator("scene.render_view_remove", icon='ZOOMOUT', text="") - - row = layout.row() - row.label(text="Camera Suffix:") - row.prop(rv, "camera_suffix", text="") - - -classes = ( - RENDERLAYER_UL_renderlayers, - RENDERLAYER_PT_layers, - RENDERLAYER_PT_layer_options, - RENDERLAYER_PT_layer_passes, - RENDERLAYER_UL_renderviews, - RENDERLAYER_PT_views, -) - -if __name__ == "__main__": # only for live edit. - from bpy.utils import register_class - for cls in classes: - register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 9b1f98ec1a4..5d87b858da6 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -17,14 +17,15 @@ # ##### END GPL LICENSE BLOCK ##### # <pep8 compliant> + import bpy from bpy.types import ( - Menu, Panel, UIList, ) from rna_prop_ui import PropertyPanel +from bl_operators.presets import PresetMenu from .properties_physics_common import ( point_cache_ui, @@ -32,12 +33,12 @@ from .properties_physics_common import ( ) -class SCENE_MT_units_length_presets(Menu): +class SCENE_PT_units_length_presets(PresetMenu): """Unit of measure for properties that use length values""" bl_label = "Unit Presets" preset_subdir = "units_length" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "scene.units_length_preset_add" class SCENE_UL_keying_set_paths(UIList): @@ -60,56 +61,48 @@ class SceneButtonsPanel: @classmethod def poll(cls, context): - rd = context.scene.render - return context.scene and (rd.engine in cls.COMPAT_ENGINES) + return (context.engine in cls.COMPAT_ENGINES) class SCENE_PT_scene(SceneButtonsPanel, Panel): bl_label = "Scene" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True scene = context.scene layout.prop(scene, "camera") - layout.prop(scene, "background_set", text="Background") - if context.scene.render.engine != 'BLENDER_GAME': - layout.prop(scene, "active_clip", text="Active Clip") + layout.prop(scene, "background_set") + layout.prop(scene, "active_clip") class SCENE_PT_unit(SceneButtonsPanel, Panel): bl_label = "Units" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header_preset(self, context): + SCENE_PT_units_length_presets.draw_panel_header(self.layout) def draw(self, context): layout = self.layout unit = context.scene.unit_settings - row = layout.row(align=True) - row.menu("SCENE_MT_units_length_presets", text=SCENE_MT_units_length_presets.bl_label) - row.operator("scene.units_length_preset_add", text="", icon='ZOOMIN') - row.operator("scene.units_length_preset_add", text="", icon='ZOOMOUT').remove_active = True + layout.use_property_split = True - layout.separator() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) - split = layout.split(percentage=0.35) - split.label("Length:") - split.prop(unit, "system", text="") - split = layout.split(percentage=0.35) - split.label("Angle:") - split.prop(unit, "system_rotation", text="") + col = flow.column() + col.prop(unit, "system") + col.prop(unit, "system_rotation") - col = layout.column() + col = flow.column() col.enabled = unit.system != 'NONE' - split = col.split(percentage=0.35) - split.label("Unit Scale:") - split.prop(unit, "scale_length", text="") - split = col.split(percentage=0.35) - split.row() - split.prop(unit, "use_separate") + col.prop(unit, "scale_length") + col.prop(unit, "use_separate") class SceneKeyingSetsPanel: @@ -155,24 +148,28 @@ class SceneKeyingSetsPanel: propname = prop row = layout.row(align=True) - row.prop(item, toggle_prop, text="", icon='STYLUS_PRESSURE', toggle=True) # XXX: needs dedicated icon - subrow = row.row() + subrow = row.row(align=True) subrow.active = getattr(item, toggle_prop) + if subrow.active: subrow.prop(item, prop, text=label) else: subrow.prop(owner, propname, text=label) + row.prop(item, toggle_prop, text="", icon='STYLUS_PRESSURE', toggle=True) # XXX: needs dedicated icon + class SCENE_PT_keying_sets(SceneButtonsPanel, SceneKeyingSetsPanel, Panel): bl_label = "Keying Sets" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout scene = context.scene + row = layout.row() col = row.column() @@ -182,25 +179,62 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, SceneKeyingSetsPanel, Panel): col.operator("anim.keying_set_add", icon='ZOOMIN', text="") col.operator("anim.keying_set_remove", icon='ZOOMOUT', text="") + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False) + ks = scene.keying_sets.active if ks and ks.is_path_absolute: - row = layout.row() - - col = row.column() + col = flow.column() col.prop(ks, "bl_description") - subcol = col.column() + subcol = flow.column() subcol.operator_context = 'INVOKE_DEFAULT' subcol.operator("anim.keying_set_export", text="Export to File").filepath = "keyingset.py" - col = row.column() - col.label(text="Keyframing Settings:") - self.draw_keyframing_settings(context, col, ks, None) + +class SCENE_PT_keyframing_settings(SceneButtonsPanel, SceneKeyingSetsPanel, Panel): + bl_label = "Keyframing Settings" + bl_parent_id = "SCENE_PT_keying_sets" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + ks = context.scene.keying_sets.active + return (ks and ks.is_path_absolute) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + scene = context.scene + ks = scene.keying_sets.active + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) + + col = flow.column(align=True) + col.alignment = 'RIGHT' + col.label(text="General Override") + + self.draw_keyframing_settings(context, col, ks, None) + + ksp = ks.paths.active + if ksp: + col.separator() + + col = flow.column(align=True) + col.alignment = 'RIGHT' + col.label(text="Active Set Override") + + self.draw_keyframing_settings(context, col, ks, ksp) class SCENE_PT_keying_set_paths(SceneButtonsPanel, SceneKeyingSetsPanel, Panel): bl_label = "Active Keying Set" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_parent_id = "SCENE_PT_keying_sets" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -225,116 +259,163 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel, SceneKeyingSetsPanel, Panel): col.operator("anim.keying_set_path_add", icon='ZOOMIN', text="") col.operator("anim.keying_set_path_remove", icon='ZOOMOUT', text="") + # TODO: 1) the template_any_ID needs to be fixed for the text alignment. + # 2) use_property_decorate has to properly skip the non animatable properties. + # Properties affected with needless draw: + # group_method, template_any_ID dropdown, use_entire_array + + layout.use_property_split = True + layout.use_property_decorate = False # No animation (remove this later on). + + flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=True) + ksp = ks.paths.active if ksp: - col = layout.column() - col.label(text="Target:") - col.template_any_ID(ksp, "id", "id_type") - col.template_path_builder(ksp, "data_path", ksp.id) - - row = col.row(align=True) - row.label(text="Array Target:") - row.prop(ksp, "use_entire_array", text="All Items") - if ksp.use_entire_array: - row.label(text=" ") # padding - else: - row.prop(ksp, "array_index", text="Index") + col = flow.column(align=True) + col.alignment = 'RIGHT' + + col.template_any_ID(ksp, "id", "id_type", text="Target ID-Block") + + col.separator() + + col.template_path_builder(ksp, "data_path", ksp.id, text="Data Path") + + col = flow.column() + + col.prop(ksp, "use_entire_array", text="Array All Items") - layout.separator() + if not ksp.use_entire_array: + col.prop(ksp, "array_index", text="Index") - row = layout.row() - col = row.column() - col.label(text="F-Curve Grouping:") - col.prop(ksp, "group_method", text="") + col.separator() + + col.prop(ksp, "group_method", text="F-Curve Grouping") if ksp.group_method == 'NAMED': col.prop(ksp, "group") - col = row.column() - col.label(text="Keyframing Settings:") - self.draw_keyframing_settings(context, col, ks, ksp) - class SCENE_PT_color_management(SceneButtonsPanel, Panel): bl_label = "Color Management" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True scene = context.scene + view = scene.view_settings - col = layout.column() - col.label(text="Display:") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) + + col = flow.column() col.prop(scene.display_settings, "display_device") - col = layout.column() col.separator() - col.label(text="Render:") - col.template_colormanaged_view_settings(scene, "view_settings") - col = layout.column() + col.prop(view, "view_transform") + col.prop(view, "look") + + col = flow.column() + col.prop(view, "exposure") + col.prop(view, "gamma") + col.separator() - col.label(text="Sequencer:") - col.prop(scene.sequencer_colorspace_settings, "name") + + col.prop(scene.sequencer_colorspace_settings, "name", text="Sequencer") + + +class SCENE_PT_color_management_curves(SceneButtonsPanel, Panel): + bl_label = "Use Curves" + bl_parent_id = "SCENE_PT_color_management" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + + scene = context.scene + view = scene.view_settings + + self.layout.prop(view, "use_curve_mapping", text="") + + def draw(self, context): + layout = self.layout + + scene = context.scene + view = scene.view_settings + + layout.use_property_split = False + layout.enabled = view.use_curve_mapping + + layout.template_curve_mapping(view, "curve_mapping", levels=True) class SCENE_PT_audio(SceneButtonsPanel, Panel): bl_label = "Audio" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True scene = context.scene rd = context.scene.render ffmpeg = rd.ffmpeg - layout.prop(scene, "audio_volume") - layout.operator("sound.bake_animation") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + + col = flow.column() + col.prop(scene, "audio_volume") + + col.separator() + + col.prop(scene, "audio_distance_model") + col.prop(ffmpeg, "audio_channels") + + col.separator() + + col = flow.column() + col.prop(ffmpeg, "audio_mixrate", text="Sample Rate") + + col.separator() - split = layout.split() + col = col.column(align=True) + col.prop(scene, "audio_doppler_speed", text="Doppler Speed") + col.prop(scene, "audio_doppler_factor", text="Doppler Factor") - col = split.column() - col.label("Distance Model:") - col.prop(scene, "audio_distance_model", text="") - sub = col.column(align=True) - sub.prop(scene, "audio_doppler_speed", text="Speed") - sub.prop(scene, "audio_doppler_factor", text="Doppler") + col.separator() - col = split.column() - col.label("Format:") - col.prop(ffmpeg, "audio_channels", text="") - col.prop(ffmpeg, "audio_mixrate", text="Rate") + layout.operator("sound.bake_animation") class SCENE_PT_physics(SceneButtonsPanel, Panel): bl_label = "Gravity" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): self.layout.prop(context.scene, "use_gravity", text="") def draw(self, context): layout = self.layout + layout.use_property_split = True scene = context.scene layout.active = scene.use_gravity - layout.prop(scene, "gravity", text="") + layout.prop(scene, "gravity") class SCENE_PT_rigid_body_world(SceneButtonsPanel, Panel): bl_label = "Rigid Body World" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - scene = context.scene - rd = scene.render - return scene and (rd.engine in cls.COMPAT_ENGINES) + return (context.engine in cls.COMPAT_ENGINES) def draw_header(self, context): scene = context.scene @@ -344,9 +425,9 @@ class SCENE_PT_rigid_body_world(SceneButtonsPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True scene = context.scene - rbw = scene.rigidbody_world if rbw is None: @@ -354,34 +435,56 @@ class SCENE_PT_rigid_body_world(SceneButtonsPanel, Panel): else: layout.operator("rigidbody.world_remove") - col = layout.column() + +class SCENE_PT_rigid_body_world_settings(SceneButtonsPanel, Panel): + bl_label = "Settings" + bl_parent_id = "SCENE_PT_rigid_body_world" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + scene = context.scene + return scene and scene.rigidbody_world and (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + rbw = scene.rigidbody_world + + if rbw: + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) + + col = flow.column() col.active = rbw.enabled col = col.column() col.prop(rbw, "group") col.prop(rbw, "constraints") - split = col.split() - - col = split.column() + col = col.column() col.prop(rbw, "time_scale", text="Speed") + + col = flow.column() + col.active = rbw.enabled col.prop(rbw, "use_split_impulse") - col = split.column() + col = col.column() col.prop(rbw, "steps_per_second", text="Steps Per Second") col.prop(rbw, "solver_iterations", text="Solver Iterations") class SCENE_PT_rigid_body_cache(SceneButtonsPanel, Panel): - bl_label = "Rigid Body Cache" + bl_label = "Cache" + bl_parent_id = "SCENE_PT_rigid_body_world" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - rd = context.scene.render scene = context.scene - return scene and scene.rigidbody_world and (rd.engine in cls.COMPAT_ENGINES) + return scene and scene.rigidbody_world and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): scene = context.scene @@ -391,15 +494,15 @@ class SCENE_PT_rigid_body_cache(SceneButtonsPanel, Panel): class SCENE_PT_rigid_body_field_weights(SceneButtonsPanel, Panel): - bl_label = "Rigid Body Field Weights" + bl_label = "Field Weights" + bl_parent_id = "SCENE_PT_rigid_body_world" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - rd = context.scene.render scene = context.scene - return scene and scene.rigidbody_world and (rd.engine in cls.COMPAT_ENGINES) + return scene and scene.rigidbody_world and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): scene = context.scene @@ -410,7 +513,8 @@ class SCENE_PT_rigid_body_field_weights(SceneButtonsPanel, Panel): class SCENE_PT_simplify(SceneButtonsPanel, Panel): bl_label = "Simplify" - COMPAT_ENGINES = {'BLENDER_RENDER'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw_header(self, context): rd = context.scene.render @@ -419,46 +523,107 @@ class SCENE_PT_simplify(SceneButtonsPanel, Panel): def draw(self, context): layout = self.layout + +class SCENE_PT_simplify_viewport(SceneButtonsPanel, Panel): + bl_label = "Viewport" + bl_parent_id = "SCENE_PT_simplify" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + rd = context.scene.render + + layout.active = rd.use_simplify + + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) + + col = flow.column() + col.prop(rd, "simplify_subdivision", text="Max Subdivision") + + col = flow.column() + col.prop(rd, "simplify_child_particles", text="Max Child Particles") + + +class SCENE_PT_simplify_render(SceneButtonsPanel, Panel): + bl_label = "Render" + bl_parent_id = "SCENE_PT_simplify" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + rd = context.scene.render layout.active = rd.use_simplify - split = layout.split() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) + + col = flow.column() + col.prop(rd, "simplify_subdivision_render", text="Max Subdivision") + + col = flow.column() + col.prop(rd, "simplify_child_particles_render", text="Max Child Particles") + - col = split.column() - col.label(text="Viewport:") - col.prop(rd, "simplify_subdivision", text="Subdivision") - col.prop(rd, "simplify_child_particles", text="Child Particles") +class SCENE_PT_simplify_greasepencil(SceneButtonsPanel, Panel): + bl_label = "Grease Pencil" + bl_parent_id = "SCENE_PT_simplify" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'} + bl_options = {'DEFAULT_CLOSED'} + + def draw_header(self, context): + rd = context.scene.render + self.layout.prop(rd, "simplify_gpencil", text="") + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + rd = context.scene.render + + layout.active = rd.simplify_gpencil + + col = layout.column() + col.prop(rd, "simplify_gpencil_onplay", text="Playback Only") + col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers") + col.prop(rd, "simplify_gpencil_shader_fx", text="ShaderFX") - col = split.column() - col.label(text="Render:") - col.prop(rd, "simplify_subdivision_render", text="Subdivision") - col.prop(rd, "simplify_child_particles_render", text="Child Particles") - col.prop(rd, "simplify_shadow_samples", text="Shadow Samples") - col.prop(rd, "simplify_ao_sss", text="AO and SSS") - col.prop(rd, "use_simplify_triangulate") + col = layout.column(align=True) + col.prop(rd, "simplify_gpencil_view_fill") + sub = col.column() + sub.active = rd.simplify_gpencil_view_fill + sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines") class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "scene" _property_type = bpy.types.Scene classes = ( - SCENE_MT_units_length_presets, + SCENE_PT_units_length_presets, SCENE_UL_keying_set_paths, SCENE_PT_scene, SCENE_PT_unit, SCENE_PT_keying_sets, SCENE_PT_keying_set_paths, + SCENE_PT_keyframing_settings, SCENE_PT_color_management, + SCENE_PT_color_management_curves, SCENE_PT_audio, SCENE_PT_physics, SCENE_PT_rigid_body_world, + SCENE_PT_rigid_body_world_settings, SCENE_PT_rigid_body_cache, SCENE_PT_rigid_body_field_weights, SCENE_PT_simplify, + SCENE_PT_simplify_viewport, + SCENE_PT_simplify_render, + SCENE_PT_simplify_greasepencil, SCENE_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index 018f3df6f0d..a4f6f753669 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -17,28 +17,27 @@ # ##### END GPL LICENSE BLOCK ##### # <pep8 compliant> -import bpy -from bpy.types import Menu, Panel, UIList +import bpy +from bpy.types import ( + Menu, + Panel, + UIList, +) from bpy.types import ( Brush, FreestyleLineStyle, - Lamp, - Material, - Object, ParticleSettings, Texture, - World, ) from rna_prop_ui import PropertyPanel - from .properties_paint_common import brush_texture_settings class TEXTURE_MT_specials(Menu): bl_label = "Texture Specials" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout @@ -47,53 +46,23 @@ class TEXTURE_MT_specials(Menu): layout.operator("texture.slot_paste", icon='PASTEDOWN') -class TEXTURE_MT_envmap_specials(Menu): - bl_label = "Environment Map Specials" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - layout.operator("texture.envmap_save", icon='IMAGEFILE') - layout.operator("texture.envmap_clear", icon='FILE_REFRESH') - layout.operator("texture.envmap_clear_all", icon='FILE_REFRESH') - - class TEXTURE_UL_texslots(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - # assert(isinstance(item, bpy.types.MaterialTextureSlot) - ma = data slot = item tex = slot.texture if slot else None + if self.layout_type in {'DEFAULT', 'COMPACT'}: if tex: layout.prop(tex, "name", text="", emboss=False, icon_value=icon) else: layout.label(text="", icon_value=icon) - if tex and isinstance(item, bpy.types.MaterialTextureSlot): - layout.prop(ma, "use_textures", text="", index=index) elif self.layout_type == 'GRID': layout.alignment = 'CENTER' layout.label(text="", icon_value=icon) -from .properties_material import active_node_mat - - def context_tex_datablock(context): - idblock = context.material - if idblock: - return active_node_mat(idblock) - - idblock = context.lamp - if idblock: - return idblock - - idblock = context.world - if idblock: - return idblock - idblock = context.brush if idblock: return idblock @@ -108,195 +77,139 @@ def context_tex_datablock(context): return idblock -def id_tex_datablock(bid): - if isinstance(bid, Object): - if bid.type == 'LAMP': - return bid.data - return bid.active_material - - return bid - - class TextureButtonsPanel: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = "texture" + +class TEXTURE_PT_preview(TextureButtonsPanel, Panel): + bl_label = "Preview" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + @classmethod def poll(cls, context): tex = context.texture - return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.scene.render.engine in cls.COMPAT_ENGINES) + return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + tex = context.texture + slot = getattr(context, "texture_slot", None) + idblock = context_tex_datablock(context) + if idblock: + layout.template_preview(tex, parent=idblock, slot=slot) + else: + layout.template_preview(tex, slot=slot) -class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel): + # Show Alpha Button for Brush Textures, see #29502 + idblock = context_tex_datablock(context) + if isinstance(idblock, Brush): + layout.prop(tex, "use_preview_alpha") + + +class TEXTURE_PT_context(TextureButtonsPanel, Panel): bl_label = "" + bl_context = "texture" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - @classmethod - def poll(cls, context): - engine = context.scene.render.engine - # if not (hasattr(context, "texture_slot") or hasattr(context, "texture_node")): - # return False - return ((context.material or - context.world or - context.lamp or - context.texture or - context.line_style or - context.particle_system or - isinstance(context.space_data.pin_id, ParticleSettings) or - context.texture_user) and - (engine in cls.COMPAT_ENGINES)) + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout - slot = getattr(context, "texture_slot", None) - node = getattr(context, "texture_node", None) - space = context.space_data tex = context.texture - idblock = context_tex_datablock(context) + space = context.space_data pin_id = space.pin_id + use_pin_id = space.use_pin_id + user = context.texture_user - space.use_limited_texture_context = True - - if space.use_pin_id and not isinstance(pin_id, Texture): - idblock = id_tex_datablock(pin_id) - pin_id = None + col = layout.column() - if not space.use_pin_id: - layout.row().prop(space, "texture_context", expand=True) + if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)): pin_id = None - if space.texture_context == 'OTHER': - if not pin_id: - layout.template_texture_user() - user = context.texture_user - if user or pin_id: - layout.separator() + if not pin_id: + col.template_texture_user() - row = layout.row() + if user or pin_id: + col.separator() - if pin_id: - row.template_ID(space, "pin_id") - else: - propname = context.texture_user_property.identifier - row.template_ID(user, propname, new="texture.new") - - if tex: - split = layout.split(percentage=0.2) - if tex.use_nodes: - if slot: - split.label(text="Output:") - split.prop(slot, "output_node", text="") - else: - split.label(text="Type:") - split.prop(tex, "type", text="") - return - - tex_collection = (pin_id is None) and (node is None) and (not isinstance(idblock, Brush)) - - if tex_collection: - row = layout.row() - - row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots", - idblock, "active_texture_index", rows=2) - - col = row.column(align=True) - col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' - col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN' - col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="") - - if tex_collection: - layout.template_ID(idblock, "active_texture", new="texture.new") - elif node: - layout.template_ID(node, "texture", new="texture.new") - elif idblock: - layout.template_ID(idblock, "texture", new="texture.new") - - if pin_id: - layout.template_ID(space, "pin_id") - - if tex: - split = layout.split(percentage=0.2) - if tex.use_nodes: - if slot: - split.label(text="Output:") - split.prop(slot, "output_node", text="") + if pin_id: + col.template_ID(space, "pin_id") else: - split.label(text="Type:") + propname = context.texture_user_property.identifier + col.template_ID(user, propname, new="texture.new") + + if tex: + col.separator() + + split = col.split(percentage=0.2) + split.label(text="Type") split.prop(tex, "type", text="") -class TEXTURE_PT_preview(TextureButtonsPanel, Panel): - bl_label = "Preview" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} +class TEXTURE_PT_node(TextureButtonsPanel, Panel): + bl_label = "Node" + bl_context = "texture" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + @classmethod + def poll(cls, context): + node = context.texture_node + return node and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout - tex = context.texture - slot = getattr(context, "texture_slot", None) - idblock = context_tex_datablock(context) + node = context.texture_node + ntree = node.id_data + layout.template_node_view(ntree, node, None) - if idblock: - layout.template_preview(tex, parent=idblock, slot=slot) - else: - layout.template_preview(tex, slot=slot) - - # Show Alpha Button for Brush Textures, see #29502 - if context.space_data.texture_context == 'BRUSH': - layout.prop(tex, "use_preview_alpha") +class TEXTURE_PT_node_mapping(TextureButtonsPanel, Panel): + bl_label = "Mapping" + bl_context = "texture" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} -class TEXTURE_PT_colors(TextureButtonsPanel, Panel): - bl_label = "Colors" - bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + @classmethod + def poll(cls, context): + node = context.texture_node + # TODO(sergey): perform a faster/nicer check? + return node and hasattr(node, 'texture_mapping') and (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False # No animation. - tex = context.texture - - layout.prop(tex, "use_color_ramp", text="Ramp") - if tex.use_color_ramp: - layout.template_color_ramp(tex, "color_ramp", expand=True) - - split = layout.split() + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) - col = split.column() - col.label(text="RGB Multiply:") - sub = col.column(align=True) - sub.prop(tex, "factor_red", text="R") - sub.prop(tex, "factor_green", text="G") - sub.prop(tex, "factor_blue", text="B") + node = context.texture_node - col = split.column() - col.label(text="Adjust:") - col.prop(tex, "intensity") - col.prop(tex, "contrast") - col.prop(tex, "saturation") - - col = layout.column() - col.prop(tex, "use_clamp", text="Clamp") + mapping = node.texture_mapping -# Texture Slot Panels # + col = flow.column() + col.prop(mapping, "vector_type") + col.separator() -class TextureSlotPanel(TextureButtonsPanel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + col = col.column(align=True) + col.prop(mapping, "mapping_x", text="Projection X") + col.prop(mapping, "mapping_y", text="Y") + col.prop(mapping, "mapping_z", text="Z") - @classmethod - def poll(cls, context): - if not hasattr(context, "texture_slot"): - return False + col.separator() - engine = context.scene.render.engine - return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES) + col = flow.column() + col.column().prop(mapping, "translation") + col = flow.column() + col.column().prop(mapping, "rotation") -# Texture Type Panels # + col = flow.column() + col.column().prop(mapping, "scale") class TextureTypePanel(TextureButtonsPanel): @@ -304,86 +217,109 @@ class TextureTypePanel(TextureButtonsPanel): @classmethod def poll(cls, context): tex = context.texture - engine = context.scene.render.engine + engine = context.engine return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES)) class TEXTURE_PT_clouds(TextureTypePanel, Panel): bl_label = "Clouds" tex_type = 'CLOUDS' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.row().prop(tex, "cloud_type", expand=True) - layout.label(text="Noise:") - layout.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") + + col.separator() + + col.prop(tex, "noise_type", text="Type") - split = layout.split() + col.separator() - col = split.column() + col = flow.column() + col.prop(tex, "cloud_type") + + col.separator() + + col = flow.column() col.prop(tex, "noise_scale", text="Size") col.prop(tex, "noise_depth", text="Depth") - - split.prop(tex, "nabla", text="Nabla") + col.prop(tex, "nabla", text="Nabla") class TEXTURE_PT_wood(TextureTypePanel, Panel): bl_label = "Wood" tex_type = 'WOOD' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=False) tex = context.texture - layout.row().prop(tex, "noise_basis_2", expand=True) - layout.row().prop(tex, "wood_type", expand=True) + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") - col = layout.column() - col.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} - col.label(text="Noise:") - col.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col.separator() - split = layout.split() - split.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} + col.prop(tex, "wood_type") - col = split.column() - col.prop(tex, "noise_scale", text="Size") - col.prop(tex, "turbulence") + col.separator() - split.prop(tex, "nabla") + col = flow.column() + col.prop(tex, "noise_basis_2", text="Second Basis") + + col = col.column() + col.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} + col.prop(tex, "noise_type", text="Type") + + col.separator() + + sub = flow.column() + sub.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'} + sub.prop(tex, "noise_scale", text="Size") + sub.prop(tex, "turbulence") + sub.prop(tex, "nabla") class TEXTURE_PT_marble(TextureTypePanel, Panel): bl_label = "Marble" tex_type = 'MARBLE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.row().prop(tex, "marble_type", expand=True) - layout.row().prop(tex, "noise_basis_2", expand=True) - layout.label(text="Noise:") - layout.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") + + col.separator() + + col.prop(tex, "marble_type") + + col.separator() + + col = flow.column() + col.prop(tex, "noise_basis_2", text="Second Basis") + col.prop(tex, "noise_type", text="Type") - split = layout.split() + col.separator() - col = split.column() + col = flow.column() col.prop(tex, "noise_scale", text="Size") col.prop(tex, "noise_depth", text="Depth") - - col = split.column() col.prop(tex, "turbulence") col.prop(tex, "nabla") @@ -391,538 +327,382 @@ class TEXTURE_PT_marble(TextureTypePanel, Panel): class TEXTURE_PT_magic(TextureTypePanel, Panel): bl_label = "Magic" tex_type = 'MAGIC' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - row = layout.row() - row.prop(tex, "noise_depth", text="Depth") - row.prop(tex, "turbulence") + col = flow.column() + col.prop(tex, "noise_depth", text="Depth") + + col = flow.column() + col.prop(tex, "turbulence") class TEXTURE_PT_blend(TextureTypePanel, Panel): bl_label = "Blend" tex_type = 'BLEND' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.prop(tex, "progression") + col = flow.column() + col.prop(tex, "progression") - sub = layout.row() + col.separator() - sub.active = (tex.progression in {'LINEAR', 'QUADRATIC', 'EASING', 'RADIAL'}) - sub.prop(tex, "use_flip_axis", expand=True) + col = flow.column() + col.active = (tex.progression in {'LINEAR', 'QUADRATIC', 'EASING', 'RADIAL'}) + col.prop(tex, "use_flip_axis", text="Orientation") class TEXTURE_PT_stucci(TextureTypePanel, Panel): bl_label = "Stucci" tex_type = 'STUCCI' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - layout.row().prop(tex, "stucci_type", expand=True) - layout.label(text="Noise:") - layout.row().prop(tex, "noise_type", text="Type", expand=True) - layout.prop(tex, "noise_basis", text="Basis") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") - row = layout.row() - row.prop(tex, "noise_scale", text="Size") - row.prop(tex, "turbulence") + col.separator() + + col.row().prop(tex, "stucci_type") + + col.separator() + + col = flow.column() + col.prop(tex, "noise_type", text="Type") + + col.separator() + + col = flow.column() + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "turbulence") class TEXTURE_PT_image(TextureTypePanel, Panel): bl_label = "Image" tex_type = 'IMAGE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): + # TODO: maybe expose the template_ID from the template image here. layout = self.layout + del layout - tex = context.texture +class TEXTURE_PT_image_settings(TextureTypePanel, Panel): + bl_label = "Settings" + bl_parent_id = 'TEXTURE_PT_image' + tex_type = 'IMAGE' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + + tex = context.texture layout.template_image(tex, "image", tex.image_user) def texture_filter_common(tex, layout): - layout.label(text="Filter:") - layout.prop(tex, "filter_type", text="") + layout.prop(tex, "filter_type", text="Filter Type") + if tex.use_mipmap and tex.filter_type in {'AREA', 'EWA', 'FELINE'}: + col = layout.column() if tex.filter_type == 'FELINE': - layout.prop(tex, "filter_probes", text="Probes") + col.prop(tex, "filter_lightprobes", text="Light Probes") else: - layout.prop(tex, "filter_eccentricity", text="Eccentricity") + col.prop(tex, "filter_eccentricity", text="Eccentricity") - layout.prop(tex, "filter_size") - layout.prop(tex, "use_filter_size_min") + layout.prop(tex, "filter_size", text="Size") + layout.prop(tex, "use_filter_size_min", text="Minimum Size") class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): - bl_label = "Image Sampling" + bl_label = "Sampling" bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'TEXTURE_PT_image' tex_type = 'IMAGE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): - if context.scene.render.engine == 'BLENDER_GAME': - self.draw_bge(context) - else: - self.draw_bi(context) - - def draw_bi(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - idblock = context_tex_datablock(context) tex = context.texture - slot = getattr(context, "texture_slot", None) - split = layout.split() + col = flow.column() + col.prop(tex, "use_interpolation") - col = split.column() - col.label(text="Alpha:") - row = col.row() - row.active = bool(tex.image and tex.image.use_alpha) - row.prop(tex, "use_alpha", text="Use") - col.prop(tex, "use_calculate_alpha", text="Calculate") - col.prop(tex, "invert_alpha", text="Invert") col.separator() - col.prop(tex, "use_flip_axis", text="Flip X/Y Axis") - col = split.column() + col = flow.column() + col.prop(tex, "use_mipmap") + sub = col.column() + sub.active = tex.use_mipmap + sub.prop(tex, "use_mipmap_gauss", text="Gaussian Filter") - # Only for Material based textures, not for Lamp/World... - if slot and isinstance(idblock, Material): - col.prop(tex, "use_normal_map") - row = col.row() - row.active = tex.use_normal_map - row.prop(slot, "normal_map_space", text="") + col.separator() - row = col.row() - row.active = not tex.use_normal_map - row.prop(tex, "use_derivative_map") + texture_filter_common(tex, flow) - col.prop(tex, "use_mipmap") - row = col.row() - row.active = tex.use_mipmap - row.prop(tex, "use_mipmap_gauss") - col.prop(tex, "use_interpolation") - texture_filter_common(tex, col) +class TEXTURE_PT_image_alpha(TextureTypePanel, Panel): + bl_label = "Alpha" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'TEXTURE_PT_image' + tex_type = 'IMAGE' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} - def draw_bge(self, context): + def draw_header(self, context): + tex = context.texture + self.layout.prop(tex, "use_alpha", text="") + + def draw(self, context): layout = self.layout + layout.use_property_split = True - idblock = context_tex_datablock(context) tex = context.texture - slot = getattr(context, "texture_slot", None) - - split = layout.split() - col = split.column() - col.label(text="Alpha:") + col = layout.column() + col.active = bool(tex.image and tex.image.use_alpha) col.prop(tex, "use_calculate_alpha", text="Calculate") col.prop(tex, "invert_alpha", text="Invert") - col = split.column() - - # Only for Material based textures, not for Lamp/World... - if slot and isinstance(idblock, Material): - col.prop(tex, "use_normal_map") - row = col.row() - row.active = tex.use_normal_map - row.prop(slot, "normal_map_space", text="") - - row = col.row() - row.active = not tex.use_normal_map - row.prop(tex, "use_derivative_map") - class TEXTURE_PT_image_mapping(TextureTypePanel, Panel): - bl_label = "Image Mapping" + bl_label = "Mapping" bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'TEXTURE_PT_image' tex_type = 'IMAGE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout + layout.use_property_split = True tex = context.texture - layout.prop(tex, "extension") - - split = layout.split() - - if tex.extension == 'REPEAT': - col = split.column(align=True) - col.label(text="Repeat:") - col.prop(tex, "repeat_x", text="X") - col.prop(tex, "repeat_y", text="Y") - - col = split.column(align=True) - col.label(text="Mirror:") - row = col.row(align=True) - row.prop(tex, "use_mirror_x", text="X") - row.active = (tex.repeat_x > 1) - row = col.row(align=True) - row.prop(tex, "use_mirror_y", text="Y") - row.active = (tex.repeat_y > 1) - layout.separator() - - elif tex.extension == 'CHECKER': - col = split.column(align=True) - row = col.row(align=True) - row.prop(tex, "use_checker_even", text="Even") - row.prop(tex, "use_checker_odd", text="Odd") - - col = split.column() - col.prop(tex, "checker_distance", text="Distance") + col = layout.column() + col.prop(tex, "use_flip_axis", text="Flip Axes") - layout.separator() + col.separator() - split = layout.split() + subcol = layout.column() + subcol.prop(tex, "extension") # use layout, to keep the same location in case of button cycling. - col = split.column(align=True) - # col.prop(tex, "crop_rectangle") - col.label(text="Crop Minimum:") - col.prop(tex, "crop_min_x", text="X") - col.prop(tex, "crop_min_y", text="Y") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) - col = split.column(align=True) - col.label(text="Crop Maximum:") - col.prop(tex, "crop_max_x", text="X") - col.prop(tex, "crop_max_y", text="Y") + if tex.extension == 'REPEAT': + col = flow.column() + sub = col.column(align=True) + sub.prop(tex, "repeat_x", text="Repeat X") + sub.prop(tex, "repeat_y", text="Y") -class TEXTURE_PT_envmap(TextureTypePanel, Panel): - bl_label = "Environment Map" - tex_type = 'ENVIRONMENT_MAP' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + col = flow.column() + sub = col.column() + sub.active = (tex.repeat_x > 1) + sub.prop(tex, "use_mirror_x", text="Mirror X") - def draw(self, context): - layout = self.layout + sub = col.column() + sub.active = (tex.repeat_y > 1) + sub.prop(tex, "use_mirror_y", text="Y") - tex = context.texture - env = tex.environment_map + elif tex.extension == 'CHECKER': + subcol.separator() - row = layout.row() - row.prop(env, "source", expand=True) - row.menu("TEXTURE_MT_envmap_specials", icon='DOWNARROW_HLT', text="") + col = flow.column() + col.prop(tex, "checker_distance", text="Distance") - if env.source == 'IMAGE_FILE': - layout.template_ID(tex, "image", open="image.open") - layout.template_image(tex, "image", tex.image_user, compact=True) + col = flow.column() + col.prop(tex, "use_checker_even", text="Tiles Even") + col.prop(tex, "use_checker_odd", text="Odd") else: - layout.prop(env, "mapping") - if env.mapping == 'PLANE': - layout.prop(env, "zoom") - layout.prop(env, "viewpoint_object") + del flow - split = layout.split() - col = split.column() - col.prop(env, "layers_ignore") - col.prop(env, "resolution") - col.prop(env, "depth") - - col = split.column(align=True) - - col.label(text="Clipping:") - col.prop(env, "clip_start", text="Start") - col.prop(env, "clip_end", text="End") - - -class TEXTURE_PT_envmap_sampling(TextureTypePanel, Panel): - bl_label = "Environment Map Sampling" +class TEXTURE_PT_image_mapping_crop(TextureTypePanel, Panel): + bl_label = "Crop" bl_options = {'DEFAULT_CLOSED'} - tex_type = 'ENVIRONMENT_MAP' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_parent_id = 'TEXTURE_PT_image_mapping' + tex_type = 'IMAGE' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - texture_filter_common(tex, layout) + col = flow.column(align=True) + # col.prop(tex, "crop_rectangle") + col.prop(tex, "crop_min_x", text="Minimum X") + col.prop(tex, "crop_min_y", text="Y") + + col = flow.column(align=True) + col.prop(tex, "crop_max_x", text="Maximum X") + col.prop(tex, "crop_max_y", text="Y") class TEXTURE_PT_musgrave(TextureTypePanel, Panel): bl_label = "Musgrave" tex_type = 'MUSGRAVE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.prop(tex, "musgrave_type") + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") + + col.separator() + + col.prop(tex, "musgrave_type") + + col.separator() - split = layout.split() + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "nabla") - col = split.column() + col.separator() + + col = flow.column() col.prop(tex, "dimension_max", text="Dimension") col.prop(tex, "lacunarity") col.prop(tex, "octaves") + col.separator() + musgrave_type = tex.musgrave_type - col = split.column() + + col = flow.column() + if musgrave_type in {'HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}: col.prop(tex, "offset") col.prop(tex, "noise_intensity", text="Intensity") + if musgrave_type in {'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}: col.prop(tex, "gain") - layout.label(text="Noise:") - - layout.prop(tex, "noise_basis", text="Basis") - - row = layout.row() - row.prop(tex, "noise_scale", text="Size") - row.prop(tex, "nabla") - class TEXTURE_PT_voronoi(TextureTypePanel, Panel): bl_label = "Voronoi" tex_type = 'VORONOI' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) tex = context.texture - split = layout.split() + col = flow.column() + col.prop(tex, "distance_metric") - col = split.column() - col.label(text="Distance Metric:") - col.prop(tex, "distance_metric", text="") sub = col.column() sub.active = tex.distance_metric == 'MINKOVSKY' sub.prop(tex, "minkovsky_exponent", text="Exponent") - col.label(text="Coloring:") - col.prop(tex, "color_mode", text="") + + sub.separator() + + col = flow.column() + col.prop(tex, "color_mode") col.prop(tex, "noise_intensity", text="Intensity") - col = split.column() - sub = col.column(align=True) - sub.label(text="Feature Weights:") - sub.prop(tex, "weight_1", text="1", slider=True) - sub.prop(tex, "weight_2", text="2", slider=True) - sub.prop(tex, "weight_3", text="3", slider=True) - sub.prop(tex, "weight_4", text="4", slider=True) + col.separator() - layout.label(text="Noise:") - row = layout.row() - row.prop(tex, "noise_scale", text="Size") - row.prop(tex, "nabla") + col = flow.column() + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "nabla") -class TEXTURE_PT_distortednoise(TextureTypePanel, Panel): - bl_label = "Distorted Noise" - tex_type = 'DISTORTED_NOISE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} +class TEXTURE_PT_voronoi_feature_weights(TextureTypePanel, Panel): + bl_label = "Feature Weights" + bl_parent_id = "TEXTURE_PT_voronoi" + tex_type = 'VORONOI' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - layout.prop(tex, "noise_distortion") - layout.prop(tex, "noise_basis", text="Basis") - - split = layout.split() - - col = split.column() - col.prop(tex, "distortion", text="Distortion") - col.prop(tex, "noise_scale", text="Size") - - split.prop(tex, "nabla") + col = flow.column(align=True) + col.prop(tex, "weight_1", text="First", slider=True) + col.prop(tex, "weight_2", text="Second", slider=True) + sub = flow.column(align=True) + sub.prop(tex, "weight_3", text="Third", slider=True) + sub.prop(tex, "weight_4", text="Fourth", slider=True) -class TEXTURE_PT_voxeldata(TextureButtonsPanel, Panel): - bl_label = "Voxel Data" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - @classmethod - def poll(cls, context): - tex = context.texture - engine = context.scene.render.engine - return tex and (tex.type == 'VOXEL_DATA' and (engine in cls.COMPAT_ENGINES)) +class TEXTURE_PT_distortednoise(TextureTypePanel, Panel): + bl_label = "Distorted Noise" + tex_type = 'DISTORTED_NOISE' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) tex = context.texture - vd = tex.voxel_data - - layout.prop(vd, "file_format") - if vd.file_format in {'BLENDER_VOXEL', 'RAW_8BIT'}: - layout.prop(vd, "filepath") - if vd.file_format == 'RAW_8BIT': - layout.prop(vd, "resolution") - elif vd.file_format == 'SMOKE': - layout.prop(vd, "domain_object") - layout.prop(vd, "smoke_data_type") - elif vd.file_format == 'HAIR': - layout.prop(vd, "domain_object") - layout.prop(vd, "hair_data_type") - elif vd.file_format == 'IMAGE_SEQUENCE': - layout.template_ID(tex, "image", open="image.open") - layout.template_image(tex, "image", tex.image_user, compact=True) - # layout.prop(vd, "frame_duration") - - if vd.file_format in {'BLENDER_VOXEL', 'RAW_8BIT'}: - layout.prop(vd, "use_still_frame") - row = layout.row() - row.active = vd.use_still_frame - row.prop(vd, "still_frame") - - layout.prop(vd, "interpolation") - layout.prop(vd, "extension") - layout.prop(vd, "intensity") - - -class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel): - bl_label = "Point Density" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - @classmethod - def poll(cls, context): - tex = context.texture - engine = context.scene.render.engine - return tex and (tex.type == 'POINT_DENSITY' and (engine in cls.COMPAT_ENGINES)) + col = flow.column() + col.prop(tex, "noise_basis", text="Noise Basis") - def draw(self, context): - layout = self.layout - - tex = context.texture - pd = tex.point_density - - layout.row().prop(pd, "point_source", expand=True) + col.separator() - split = layout.split() + col.prop(tex, "noise_distortion", text="Distortion") - col = split.column() - if pd.point_source == 'PARTICLE_SYSTEM': - col.label(text="Object:") - col.prop(pd, "object", text="") + col.separator() - sub = col.column() - sub.enabled = bool(pd.object) - if pd.object: - sub.label(text="System:") - sub.prop_search(pd, "particle_system", pd.object, "particle_systems", text="") - sub.label(text="Cache:") - sub.prop(pd, "particle_cache_space", text="") - else: - col.label(text="Object:") - col.prop(pd, "object", text="") - col.label(text="Cache:") - col.prop(pd, "vertex_cache_space", text="") + col = flow.column() + col.prop(tex, "distortion", text="Amount") + col.prop(tex, "noise_scale", text="Size") + col.prop(tex, "nabla") - col.separator() - col.label(text="Color Source:") - if pd.point_source == 'PARTICLE_SYSTEM': - col.prop(pd, "particle_color_source", text="") - if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_VELOCITY'}: - col.prop(pd, "speed_scale") - if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_AGE'}: - layout.template_color_ramp(pd, "color_ramp", expand=True) - else: - col.prop(pd, "vertex_color_source", text="") - if pd.vertex_color_source == 'VERTEX_COLOR': - if pd.object and pd.object.data: - col.prop_search(pd, "vertex_attribute_name", pd.object.data, "vertex_colors", text="") - if pd.vertex_color_source == 'VERTEX_WEIGHT': - if pd.object: - col.prop_search(pd, "vertex_attribute_name", pd.object, "vertex_groups", text="") - layout.template_color_ramp(pd, "color_ramp", expand=True) - - col = split.column() - col.label() - col.prop(pd, "radius") - col.label(text="Falloff:") - col.prop(pd, "falloff", text="") - if pd.falloff == 'SOFT': - col.prop(pd, "falloff_soft") - if pd.falloff == 'PARTICLE_VELOCITY': - col.prop(pd, "falloff_speed_scale") - - col.prop(pd, "use_falloff_curve") - - if pd.use_falloff_curve: - col = layout.column() - col.label(text="Falloff Curve") - col.template_curve_mapping(pd, "falloff_curve", brush=False) - - -class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, Panel): - bl_label = "Turbulence" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} +class TextureSlotPanel(TextureButtonsPanel): + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - tex = context.texture - engine = context.scene.render.engine - return tex and (tex.type == 'POINT_DENSITY' and (engine in cls.COMPAT_ENGINES)) - - def draw_header(self, context): - pd = context.texture.point_density - - self.layout.prop(pd, "use_turbulence", text="") - - def draw(self, context): - layout = self.layout - - tex = context.texture - pd = tex.point_density - layout.active = pd.use_turbulence - - split = layout.split() - - col = split.column() - col.label(text="Influence:") - col.prop(pd, "turbulence_influence", text="") - col.label(text="Noise Basis:") - col.prop(pd, "noise_basis", text="") - - col = split.column() - col.label() - col.prop(pd, "turbulence_scale") - col.prop(pd, "turbulence_depth") - col.prop(pd, "turbulence_strength") - - -class TEXTURE_PT_ocean(TextureTypePanel, Panel): - bl_label = "Ocean" - tex_type = 'OCEAN' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - tex = context.texture - ot = tex.ocean + if not hasattr(context, "texture_slot"): + return False - col = layout.column() - col.prop(ot, "ocean_object") - col.prop(ot, "output") + return (context.engine in cls.COMPAT_ENGINES) class TEXTURE_PT_mapping(TextureSlotPanel, Panel): bl_label = "Mapping" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -933,99 +713,70 @@ class TEXTURE_PT_mapping(TextureSlotPanel, Panel): if not getattr(context, "texture_slot", None): return False - engine = context.scene.render.engine + engine = context.engine return (engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True) idblock = context_tex_datablock(context) tex = context.texture_slot - if not isinstance(idblock, Brush): - split = layout.split(percentage=0.3) - col = split.column() - col.label(text="Coordinates:") - col = split.column() - col.prop(tex, "texture_coords", text="") + if isinstance(idblock, Brush): + if context.sculpt_object or context.image_paint_object: + brush_texture_settings(layout, idblock, context.sculpt_object) + else: + col = flow.column() - if tex.texture_coords == 'ORCO': - """ - ob = context.object - if ob and ob.type == 'MESH': - split = layout.split(percentage=0.3) - split.label(text="Mesh:") - split.prop(ob.data, "texco_mesh", text="") - """ - elif tex.texture_coords == 'UV': - split = layout.split(percentage=0.3) - split.label(text="Map:") + col.prop(tex, "texture_coords", text="Coordinates") + + # Note: the ORCO case used to call ob.data, "texco_mesh" prop. + if tex.texture_coords == 'UV': ob = context.object + if ob and ob.type == 'MESH': - split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="") + # Note: TODO prop_search doesn't align on the right. + row = col.row(align=True) + row.prop_search(tex, "uv_layer", ob.data, "uv_layers", text="Map") + row.label(text="", icon='BLANK1') else: - split.prop(tex, "uv_layer", text="") + col.prop(tex, "uv_layer", text="Map") elif tex.texture_coords == 'OBJECT': - split = layout.split(percentage=0.3) - split.label(text="Object:") - split.prop(tex, "object", text="") + col.prop(tex, "object", text="Object") elif tex.texture_coords == 'ALONG_STROKE': - split = layout.split(percentage=0.3) - split.label(text="Use Tips:") - split.prop(tex, "use_tips", text="") + col.prop(tex, "use_tips", text="Use Tips") + + col.separator() - if isinstance(idblock, Brush): - if context.sculpt_object or context.image_paint_object: - brush_texture_settings(layout, idblock, context.sculpt_object) - else: if isinstance(idblock, FreestyleLineStyle): - split = layout.split(percentage=0.3) - split.label(text="Projection:") - split.prop(tex, "mapping", text="") - - split = layout.split(percentage=0.3) - split.separator() - row = split.row() - row.prop(tex, "mapping_x", text="") - row.prop(tex, "mapping_y", text="") - row.prop(tex, "mapping_z", text="") - - elif isinstance(idblock, Material): - split = layout.split(percentage=0.3) - split.label(text="Projection:") - split.prop(tex, "mapping", text="") - - split = layout.split() - - col = split.column() - if tex.texture_coords in {'ORCO', 'UV'}: - col.prop(tex, "use_from_dupli") - if (idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO'): - col.prop(tex, "use_map_to_bounds") - elif tex.texture_coords == 'OBJECT': - col.prop(tex, "use_from_original") - if (idblock.type == 'VOLUME'): - col.prop(tex, "use_map_to_bounds") - else: - col.label() + col = flow.column() + col.prop(tex, "mapping", text="Projection") - col = split.column() - row = col.row() - row.prop(tex, "mapping_x", text="") - row.prop(tex, "mapping_y", text="") - row.prop(tex, "mapping_z", text="") + col.separator() - row = layout.row() - row.column().prop(tex, "offset") - row.column().prop(tex, "scale") + col = flow.column() + col.prop(tex, "mapping_x", text="Mapping X") + col.prop(tex, "mapping_y", text="Y") + col.prop(tex, "mapping_z", text="Z") + + col.separator() + + col = flow.column(align=True) + col.column().prop(tex, "offset") + + col = flow.column(align=True) + col.column().prop(tex, "scale") class TEXTURE_PT_influence(TextureSlotPanel, Panel): bl_label = "Influence" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): @@ -1036,215 +787,149 @@ class TEXTURE_PT_influence(TextureSlotPanel, Panel): if not getattr(context, "texture_slot", None): return False - engine = context.scene.render.engine + engine = context.engine return (engine in cls.COMPAT_ENGINES) def draw(self, context): - layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False) idblock = context_tex_datablock(context) - tex = context.texture_slot def factor_but(layout, toggle, factor, name): row = layout.row(align=True) - row.prop(tex, toggle, text="") + row.active = getattr(tex, toggle) + + row.prop(tex, factor, text=name, slider=True) sub = row.row(align=True) - sub.active = getattr(tex, toggle) - sub.prop(tex, factor, text=name, slider=True) + sub.prop(tex, toggle, text="") return sub # XXX, temp. use_map_normal needs to override. - if isinstance(idblock, Material): - if idblock.type in {'SURFACE', 'WIRE'}: - split = layout.split() - - col = split.column() - col.label(text="Diffuse:") - factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity") - factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") - factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") - factor_but(col, "use_map_translucency", "translucency_factor", "Translucency") - - col.label(text="Specular:") - factor_but(col, "use_map_specular", "specular_factor", "Intensity") - factor_but(col, "use_map_color_spec", "specular_color_factor", "Color") - factor_but(col, "use_map_hardness", "hardness_factor", "Hardness") - - col = split.column() - col.label(text="Shading:") - factor_but(col, "use_map_ambient", "ambient_factor", "Ambient") - factor_but(col, "use_map_emit", "emit_factor", "Emit") - factor_but(col, "use_map_mirror", "mirror_factor", "Mirror") - factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror") - - col.label(text="Geometry:") - # XXX replace 'or' when displacement is fixed to not rely on normal influence value. - sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal") - sub_tmp.active = (tex.use_map_normal or tex.use_map_displacement) - # END XXX - - factor_but(col, "use_map_warp", "warp_factor", "Warp") - factor_but(col, "use_map_displacement", "displacement_factor", "Displace") - - # ~ sub = col.column() - # ~ sub.active = tex.use_map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror - #~ sub.prop(tex, "default_value", text="Amount", slider=True) - elif idblock.type == 'HALO': - layout.label(text="Halo:") - - split = layout.split() - - col = split.column() - factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") - factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") - - col = split.column() - factor_but(col, "use_map_raymir", "raymir_factor", "Size") - factor_but(col, "use_map_hardness", "hardness_factor", "Hardness") - factor_but(col, "use_map_translucency", "translucency_factor", "Add") - elif idblock.type == 'VOLUME': - layout.label(text="Volume:") - - split = layout.split() - - col = split.column() - factor_but(col, "use_map_density", "density_factor", "Density") - factor_but(col, "use_map_emission", "emission_factor", "Emission") - factor_but(col, "use_map_scatter", "scattering_factor", "Scattering") - factor_but(col, "use_map_reflect", "reflection_factor", "Reflection") - - col = split.column() - col.label(text=" ") - factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color") - factor_but(col, "use_map_color_transmission", "transmission_color_factor", "Transmission Color") - factor_but(col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color") - - layout.label(text="Geometry:") - - split = layout.split() - - col = split.column() - factor_but(col, "use_map_warp", "warp_factor", "Warp") - - col = split.column() - factor_but(col, "use_map_displacement", "displacement_factor", "Displace") - - elif isinstance(idblock, Lamp): - split = layout.split() - - col = split.column() - factor_but(col, "use_map_color", "color_factor", "Color") - - col = split.column() - factor_but(col, "use_map_shadow", "shadow_factor", "Shadow") - - elif isinstance(idblock, World): - split = layout.split() - - col = split.column() - factor_but(col, "use_map_blend", "blend_factor", "Blend") - factor_but(col, "use_map_horizon", "horizon_factor", "Horizon") - - col = split.column() - factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up") - factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down") - elif isinstance(idblock, ParticleSettings): - split = layout.split() - - col = split.column() - col.label(text="General:") - factor_but(col, "use_map_time", "time_factor", "Time") + if isinstance(idblock, ParticleSettings): + col = flow.column() + factor_but(col, "use_map_time", "time_factor", "General Time") factor_but(col, "use_map_life", "life_factor", "Lifetime") factor_but(col, "use_map_density", "density_factor", "Density") factor_but(col, "use_map_size", "size_factor", "Size") - col = split.column() - col.label(text="Physics:") - factor_but(col, "use_map_velocity", "velocity_factor", "Velocity") + col.separator() + + col = flow.column() + factor_but(col, "use_map_velocity", "velocity_factor", "Physics Velocity") factor_but(col, "use_map_damp", "damp_factor", "Damp") factor_but(col, "use_map_gravity", "gravity_factor", "Gravity") factor_but(col, "use_map_field", "field_factor", "Force Fields") - layout.label(text="Hair:") + col.separator() - split = layout.split() - - col = split.column() - factor_but(col, "use_map_length", "length_factor", "Length") + col = flow.column() + factor_but(col, "use_map_length", "length_factor", "Hair Length") factor_but(col, "use_map_clump", "clump_factor", "Clump") factor_but(col, "use_map_twist", "twist_factor", "Twist") - col = split.column() + col = flow.column() factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude") factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency") factor_but(col, "use_map_rough", "rough_factor", "Rough") elif isinstance(idblock, FreestyleLineStyle): - split = layout.split() - - col = split.column() + col = flow.column() factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") - col = split.column() factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") - layout.separator() - if not isinstance(idblock, ParticleSettings): - split = layout.split() + col = flow.column() - col = split.column() col.prop(tex, "blend_type", text="Blend") col.prop(tex, "use_rgb_to_intensity") + # color is used on gray-scale textures even when use_rgb_to_intensity is disabled. col.prop(tex, "color", text="") - col = split.column() + col = flow.column() col.prop(tex, "invert", text="Negative") col.prop(tex, "use_stencil") - if isinstance(idblock, (Material, World)): - col.prop(tex, "default_value", text="DVar", slider=True) - if isinstance(idblock, Material): - layout.label(text="Bump Mapping:") +class TextureColorsPoll: + @classmethod + def poll(cls, context): + tex = context.texture + return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES) + + +class TEXTURE_PT_colors(TextureButtonsPanel, TextureColorsPoll, Panel): + bl_label = "Colors" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False) + + tex = context.texture - # only show bump settings if activated but not for normal-map images - row = layout.row() + col = flow.column() + col.prop(tex, "use_clamp", text="Clamp") - sub = row.row() - sub.active = ( - (tex.use_map_normal or tex.use_map_warp) and - not (tex.texture.type == 'IMAGE' and - (tex.texture.use_normal_map or tex.texture.use_derivative_map)) - ) - sub.prop(tex, "bump_method", text="Method") + col = flow.column(align=True) + col.prop(tex, "factor_red", text="Multiply R") + col.prop(tex, "factor_green", text="G") + col.prop(tex, "factor_blue", text="B") - # the space setting is supported for: derivative-maps + bump-maps - # (DEFAULT,BEST_QUALITY), not for normal-maps - sub = row.row() - sub.active = ( - (tex.use_map_normal or tex.use_map_warp) and - not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) and - ((tex.bump_method in {'BUMP_LOW_QUALITY', 'BUMP_MEDIUM_QUALITY', 'BUMP_BEST_QUALITY'}) or - (tex.texture.type == 'IMAGE' and tex.texture.use_derivative_map)) - ) - sub.prop(tex, "bump_objectspace", text="Space") + col.separator() + + col = flow.column() + col.prop(tex, "intensity") + col.prop(tex, "contrast") + col.prop(tex, "saturation") + + +class TEXTURE_PT_colors_ramp(TextureButtonsPanel, TextureColorsPoll, Panel): + bl_label = "Color Ramp" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'TEXTURE_PT_colors' + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw_header(self, context): + tex = context.texture + self.layout.prop(tex, "use_color_ramp", text="") + + def draw(self, context): + layout = self.layout + + tex = context.texture + + # Note: TODO after creation of a new texture, the template_color_ramp will be blank. + # Possibly needs to be fixed in the template itself. + is_active = bool(tex and tex.use_color_ramp) + if is_active: + layout.template_color_ramp(tex, "color_ramp", expand=True) + else: + layout.alignment = 'RIGHT' + layout.label("Please enable the Color Ramp first") class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "texture" _property_type = Texture + @classmethod + def poll(cls, context): + return context.texture and (context.engine in cls.COMPAT_ENGINES) + classes = ( TEXTURE_MT_specials, - TEXTURE_MT_envmap_specials, TEXTURE_UL_texslots, - TEXTURE_PT_context_texture, TEXTURE_PT_preview, - TEXTURE_PT_colors, + TEXTURE_PT_context, + TEXTURE_PT_node, + TEXTURE_PT_node_mapping, TEXTURE_PT_clouds, TEXTURE_PT_wood, TEXTURE_PT_marble, @@ -1252,19 +937,19 @@ classes = ( TEXTURE_PT_blend, TEXTURE_PT_stucci, TEXTURE_PT_image, - TEXTURE_PT_image_sampling, + TEXTURE_PT_image_settings, + TEXTURE_PT_image_alpha, TEXTURE_PT_image_mapping, - TEXTURE_PT_envmap, - TEXTURE_PT_envmap_sampling, + TEXTURE_PT_image_mapping_crop, + TEXTURE_PT_image_sampling, TEXTURE_PT_musgrave, TEXTURE_PT_voronoi, + TEXTURE_PT_voronoi_feature_weights, TEXTURE_PT_distortednoise, - TEXTURE_PT_voxeldata, - TEXTURE_PT_pointdensity, - TEXTURE_PT_pointdensity_turbulence, - TEXTURE_PT_ocean, - TEXTURE_PT_mapping, TEXTURE_PT_influence, + TEXTURE_PT_mapping, + TEXTURE_PT_colors, + TEXTURE_PT_colors_ramp, TEXTURE_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py new file mode 100644 index 00000000000..f96bf041311 --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -0,0 +1,82 @@ +# ##### 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> +import bpy +from bpy.types import Panel, UIList + + +class ViewLayerButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "view_layer" + # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + +class VIEWLAYER_PT_layer(ViewLayerButtonsPanel, Panel): + bl_label = "View Layer" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + rd = scene.render + layer = bpy.context.view_layer + + layout.prop(layer, "use", text="Use for Rendering") + layout.prop(rd, "use_single_layer", text="Render Single Layer") + + +class VIEWLAYER_PT_eevee_layer_passes(ViewLayerButtonsPanel, Panel): + bl_label = "Passes" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + rd = scene.render + view_layer = context.view_layer + + col = layout.column() + col.prop(view_layer, "use_pass_combined") + col.prop(view_layer, "use_pass_z") + col.prop(view_layer, "use_pass_mist") + col.prop(view_layer, "use_pass_normal") + col.prop(view_layer, "use_pass_ambient_occlusion") + col.prop(view_layer, "use_pass_subsurface_direct", text="Subsurface Direct") + col.prop(view_layer, "use_pass_subsurface_color", text="Subsurface Color") + + +classes = ( + VIEWLAYER_PT_layer, + VIEWLAYER_PT_eevee_layer_passes, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py index 107c31567b3..7395fa13d9a 100644 --- a/release/scripts/startup/bl_ui/properties_world.py +++ b/release/scripts/startup/bl_ui/properties_world.py @@ -20,6 +20,7 @@ import bpy from bpy.types import Panel from rna_prop_ui import PropertyPanel +from bpy_extras.node_utils import find_node_input class WorldButtonsPanel: @@ -30,18 +31,17 @@ class WorldButtonsPanel: @classmethod def poll(cls, context): - return (context.world and context.scene.render.engine in cls.COMPAT_ENGINES) + return (context.world and context.engine in cls.COMPAT_ENGINES) class WORLD_PT_context_world(WorldButtonsPanel, Panel): bl_label = "" bl_options = {'HIDE_HEADER'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} @classmethod def poll(cls, context): - rd = context.scene.render - return rd.engine in cls.COMPAT_ENGINES + return (context.engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout @@ -50,214 +50,97 @@ class WORLD_PT_context_world(WorldButtonsPanel, Panel): world = context.world space = context.space_data - texture_count = world and len(world.texture_slots.keys()) - - split = layout.split(percentage=0.85) if scene: - split.template_ID(scene, "world", new="world.new") + layout.template_ID(scene, "world", new="world.new") elif world: - split.template_ID(space, "pin_id") - - if texture_count: - split.label(text=str(texture_count), icon='TEXTURE') + layout.template_ID(space, "pin_id") -class WORLD_PT_preview(WorldButtonsPanel, Panel): - bl_label = "Preview" - COMPAT_ENGINES = {'BLENDER_RENDER'} +class EEVEE_WORLD_PT_mist(WorldButtonsPanel, Panel): + bl_label = "Mist Pass" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} @classmethod def poll(cls, context): - rd = context.scene.render - return (context.world) and (rd.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - self.layout.template_preview(context.world) - + engine = context.engine + if context.world and (engine in cls.COMPAT_ENGINES): + for view_layer in context.scene.view_layers: + if view_layer.use_pass_mist: + return True -class WORLD_PT_world(WorldButtonsPanel, Panel): - bl_label = "World" - COMPAT_ENGINES = {'BLENDER_RENDER'} + return False def draw(self, context): layout = self.layout + layout.use_property_split = True world = context.world - row = layout.row() - row.prop(world, "use_sky_paper") - row.prop(world, "use_sky_blend") - row.prop(world, "use_sky_real") - - row = layout.row() - row.column().prop(world, "horizon_color") - col = row.column() - col.prop(world, "zenith_color") - col.active = world.use_sky_blend - row.column().prop(world, "ambient_color") - - row = layout.row() - row.prop(world, "exposure") - row.prop(world, "color_range") - - -class WORLD_PT_ambient_occlusion(WorldButtonsPanel, Panel): - bl_label = "Ambient Occlusion" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw_header(self, context): - light = context.world.light_settings - self.layout.prop(light, "use_ambient_occlusion", text="") - - def draw(self, context): - layout = self.layout - - light = context.world.light_settings - - layout.active = light.use_ambient_occlusion - - split = layout.split() - split.prop(light, "ao_factor", text="Factor") - split.prop(light, "ao_blend_type", text="") - - -class WORLD_PT_environment_lighting(WorldButtonsPanel, Panel): - bl_label = "Environment Lighting" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw_header(self, context): - light = context.world.light_settings - self.layout.prop(light, "use_environment_light", text="") - - def draw(self, context): - layout = self.layout - - light = context.world.light_settings - - layout.active = light.use_environment_light - - split = layout.split() - split.prop(light, "environment_energy", text="Energy") - split.prop(light, "environment_color", text="") - - -class WORLD_PT_indirect_lighting(WorldButtonsPanel, Panel): - bl_label = "Indirect Lighting" - COMPAT_ENGINES = {'BLENDER_RENDER'} - - def draw_header(self, context): - light = context.world.light_settings - self.layout.prop(light, "use_indirect_light", text="") - - def draw(self, context): - layout = self.layout - - light = context.world.light_settings + layout.prop(world.mist_settings, "start") + layout.prop(world.mist_settings, "depth") + layout.prop(world.mist_settings, "falloff") - layout.active = light.use_indirect_light and light.gather_method == 'APPROXIMATE' - split = layout.split() - split.prop(light, "indirect_factor", text="Factor") - split.prop(light, "indirect_bounces", text="Bounces") +class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} + _context_path = "world" + _property_type = bpy.types.World - if light.gather_method == 'RAYTRACE': - layout.label(text="Only works with Approximate gather method") +class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel): + bl_label = "Surface" + COMPAT_ENGINES = {'BLENDER_EEVEE'} -class WORLD_PT_gather(WorldButtonsPanel, Panel): - bl_label = "Gather" - COMPAT_ENGINES = {'BLENDER_RENDER'} + @classmethod + def poll(cls, context): + engine = context.engine + return context.world and (engine in cls.COMPAT_ENGINES) def draw(self, context): layout = self.layout - light = context.world.light_settings - - layout.active = light.use_ambient_occlusion or light.use_environment_light or light.use_indirect_light - - layout.row().prop(light, "gather_method", expand=True) - - split = layout.split() - - col = split.column() - col.label(text="Attenuation:") - if light.gather_method == 'RAYTRACE': - col.prop(light, "distance") - col.prop(light, "use_falloff") - sub = col.row() - sub.active = light.use_falloff - sub.prop(light, "falloff_strength", text="Strength") - - if light.gather_method == 'RAYTRACE': - col = split.column() - - col.label(text="Sampling:") - col.prop(light, "sample_method", text="") - - sub = col.column() - sub.prop(light, "samples") + world = context.world - if light.sample_method == 'ADAPTIVE_QMC': - sub.prop(light, "threshold") - sub.prop(light, "adapt_to_speed", slider=True) - elif light.sample_method == 'CONSTANT_JITTERED': - sub.prop(light, "bias") + layout.prop(world, "use_nodes", icon='NODETREE') + layout.separator() - if light.gather_method == 'APPROXIMATE': - col = split.column() + if world.use_nodes: + ntree = world.node_tree + node = ntree.get_output_node('EEVEE') - col.label(text="Sampling:") - col.prop(light, "passes") - col.prop(light, "error_threshold", text="Error") - col.prop(light, "use_cache") - col.prop(light, "correction") + if node: + input = find_node_input(node, 'Surface') + if input: + layout.template_node_view(ntree, node, input) + else: + layout.label(text="Incompatible output node") + else: + layout.label(text="No output node") + else: + layout.prop(world, "color") -class WORLD_PT_mist(WorldButtonsPanel, Panel): - bl_label = "Mist" +class WORLD_PT_viewport_display(WorldButtonsPanel, Panel): + bl_label = "Viewport Display" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} - def draw_header(self, context): - world = context.world - - self.layout.prop(world.mist_settings, "use_mist", text="") + @classmethod + def poll(cls, context): + return context.world def draw(self, context): layout = self.layout - + layout.use_property_split = True world = context.world - - layout.active = world.mist_settings.use_mist - - split = layout.split() - - col = split.column() - col.prop(world.mist_settings, "intensity") - col.prop(world.mist_settings, "start") - - col = split.column() - col.prop(world.mist_settings, "depth") - col.prop(world.mist_settings, "height") - - layout.prop(world.mist_settings, "falloff") - - -class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} - _context_path = "world" - _property_type = bpy.types.World + layout.prop(world, "color") classes = ( WORLD_PT_context_world, - WORLD_PT_preview, - WORLD_PT_world, - WORLD_PT_ambient_occlusion, - WORLD_PT_environment_lighting, - WORLD_PT_indirect_lighting, - WORLD_PT_gather, - WORLD_PT_mist, + EEVEE_WORLD_PT_surface, + EEVEE_WORLD_PT_mist, + WORLD_PT_viewport_display, WORLD_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index f8d9ae3ef9f..1564204c613 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -21,14 +21,10 @@ import bpy from bpy.types import Panel, Header, Menu, UIList from bpy.app.translations import pgettext_iface as iface_ +from bl_operators.presets import PresetMenu from .properties_grease_pencil_common import ( GreasePencilDrawingToolsPanel, - GreasePencilStrokeEditPanel, - GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel, GreasePencilDataPanel, - GreasePencilPaletteColorPanel, ) @@ -57,21 +53,20 @@ class CLIP_HT_header(Header): sc = context.space_data clip = sc.clip - row = layout.row(align=True) - row.template_header() - CLIP_MT_tracking_editor_menus.draw_collapsible(context, layout) + layout.separator_spacer() + row = layout.row() row.template_ID(sc, "clip", open="clip.open") + layout.separator_spacer() + if clip: tracking = clip.tracking active_object = tracking.objects.active if sc.view == 'CLIP': - layout.prop(sc, "mode", text="") - layout.prop(sc, "view", text="", expand=True) layout.prop(sc, "pivot_point", text="", icon_only=True) r = active_object.reconstruction @@ -80,8 +75,6 @@ class CLIP_HT_header(Header): layout.label(text="Solve error: %.4f" % (r.average_error)) elif sc.view == 'GRAPH': - layout.prop(sc, "view", text="", expand=True) - row = layout.row(align=True) row.prop(sc, "show_graph_only_selected", text="") row.prop(sc, "show_graph_hidden", text="") @@ -103,7 +96,6 @@ class CLIP_HT_header(Header): text="Filters") elif sc.view == 'DOPESHEET': dopesheet = tracking.dopesheet - layout.prop(sc, "view", text="", expand=True) row = layout.row(align=True) row.prop(dopesheet, "show_only_selected", text="") @@ -113,8 +105,6 @@ class CLIP_HT_header(Header): row.prop(dopesheet, "sort_method", text="") row.prop(dopesheet, "use_invert_sort", text="Invert", toggle=True) - else: - layout.prop(sc, "view", text="", expand=True) def _draw_masking(self, context): layout = self.layout @@ -123,35 +113,40 @@ class CLIP_HT_header(Header): sc = context.space_data clip = sc.clip - row = layout.row(align=True) - row.template_header() - CLIP_MT_masking_editor_menus.draw_collapsible(context, layout) + layout.separator_spacer() + row = layout.row() row.template_ID(sc, "clip", open="clip.open") - if clip: - layout.prop(sc, "mode", text="") + layout.separator_spacer() + if clip: row = layout.row() row.template_ID(sc, "mask", new="mask.new") + layout.separator_spacer() + layout.prop(sc, "pivot_point", text="", icon_only=True) row = layout.row(align=True) - row.prop(toolsettings, "use_proportional_edit_mask", - text="", icon_only=True) - if toolsettings.use_proportional_edit_mask: - row.prop(toolsettings, "proportional_edit_falloff", - text="", icon_only=True) + row.prop(toolsettings, "use_proportional_edit_mask", text="", icon_only=True) + sub = row.row(align=True) + sub.active = toolsettings.use_proportional_edit_mask + sub.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True) def draw(self, context): layout = self.layout sc = context.space_data + row = layout.row(align=True) + row.template_header() + + layout.prop(sc, "mode", text="") if sc.mode == 'TRACKING': + layout.prop(sc, "view", text="") self._draw_tracking(context) else: self._draw_masking(context) @@ -284,6 +279,9 @@ class CLIP_PT_tracking_settings(CLIP_PT_tracking_panel, Panel): bl_label = "Tracking Settings" bl_category = "Track" + def draw_header_preset(self, context): + CLIP_PT_tracking_settings_presets.draw_panel_header(self.layout) + def draw(self, context): sc = context.space_data @@ -293,14 +291,6 @@ class CLIP_PT_tracking_settings(CLIP_PT_tracking_panel, Panel): col = layout.column() row = col.row(align=True) - label = CLIP_MT_tracking_settings_presets.bl_label - row.menu('CLIP_MT_tracking_settings_presets', text=label) - row.operator("clip.tracking_settings_preset_add", - text="", icon='ZOOMIN') - row.operator("clip.tracking_settings_preset_add", - text="", icon='ZOOMOUT').remove_active = True - - row = col.row(align=True) row.prop(settings, "use_default_red_channel", text="R", toggle=True) row.prop(settings, "use_default_green_channel", @@ -632,12 +622,8 @@ class CLIP_PT_track(CLIP_PT_tracking_panel, Panel): layout.separator() row = layout.row(align=True) - label = bpy.types.CLIP_MT_track_color_presets.bl_label - row.menu('CLIP_MT_track_color_presets', text=label) + CLIP_PT_track_color_presets.draw_menu(row, 'Color Presets') row.menu('CLIP_MT_track_color_specials', text="", icon='DOWNARROW_HLT') - row.operator("clip.track_color_preset_add", text="", icon='ZOOMIN') - row.operator("clip.track_color_preset_add", - text="", icon='ZOOMOUT').remove_active = True row = layout.row() row.prop(act_track, "use_custom_color") @@ -727,19 +713,15 @@ class CLIP_PT_tracking_camera(Panel): return False + def draw_header_preset(self, context): + CLIP_PT_camera_presets.draw_panel_header(self.layout) + def draw(self, context): layout = self.layout sc = context.space_data clip = sc.clip - row = layout.row(align=True) - label = bpy.types.CLIP_MT_camera_presets.bl_label - row.menu('CLIP_MT_camera_presets', text=label) - row.operator("clip.camera_preset_add", text="", icon='ZOOMIN') - row.operator("clip.camera_preset_add", text="", - icon='ZOOMOUT').remove_active = True - col = layout.column(align=True) col.label(text="Sensor:") col.prop(clip.tracking.camera, "sensor_width", text="Width") @@ -1167,39 +1149,10 @@ class CLIP_PT_grease_pencil(GreasePencilDataPanel, CLIP_PT_clip_view_panel, Pane # But, this should only be visible in "clip" view -# Grease Pencil palette colors -class CLIP_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, CLIP_PT_clip_view_panel, Panel): - bl_space_type = 'CLIP_EDITOR' - bl_region_type = 'UI' - bl_options = {'DEFAULT_CLOSED'} - - # NOTE: this is just a wrapper around the generic GP Panel - # But, this should only be visible in "clip" view - - # Grease Pencil drawing tools class CLIP_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil stroke editing tools -class CLIP_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): - bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil stroke sculpting tools -class CLIP_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil drawing brushes -class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'CLIP_EDITOR' - - -# Grease Pencil drawing curves -class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): - bl_space_type = 'CLIP_EDITOR' + bl_region_type = 'TOOLS' class CLIP_MT_view(Menu): @@ -1245,9 +1198,8 @@ class CLIP_MT_view(Menu): layout.prop(sc, "show_locked_time") layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + + layout.menu("INFO_MT_area") class CLIP_MT_clip(Menu): @@ -1439,28 +1391,28 @@ class CLIP_MT_tracking_specials(Menu): text="Unlock Tracks").action = 'UNLOCK' -class CLIP_MT_camera_presets(Menu): +class CLIP_PT_camera_presets(PresetMenu): """Predefined tracking camera intrinsics""" bl_label = "Camera Presets" preset_subdir = "tracking_camera" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "clip.camera_preset_add" -class CLIP_MT_track_color_presets(Menu): +class CLIP_PT_track_color_presets(PresetMenu): """Predefined track color""" bl_label = "Color Presets" preset_subdir = "tracking_track_color" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "clip.track_color_preset_add" -class CLIP_MT_tracking_settings_presets(Menu): +class CLIP_PT_tracking_settings_presets(PresetMenu): """Predefined tracking settings""" bl_label = "Tracking Presets" preset_subdir = "tracking_settings" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "clip.tracking_settings_preset_add" class CLIP_MT_track_color_specials(Menu): @@ -1529,12 +1481,7 @@ classes = ( CLIP_PT_footage_info, CLIP_PT_tools_scenesetup, CLIP_PT_grease_pencil, - CLIP_PT_grease_pencil_palettecolor, CLIP_PT_tools_grease_pencil_draw, - CLIP_PT_tools_grease_pencil_edit, - CLIP_PT_tools_grease_pencil_sculpt, - CLIP_PT_tools_grease_pencil_brush, - CLIP_PT_tools_grease_pencil_brushcurves, CLIP_MT_view, CLIP_MT_clip, CLIP_MT_proxy, @@ -1544,9 +1491,9 @@ classes = ( CLIP_MT_select, CLIP_MT_select_grouped, CLIP_MT_tracking_specials, - CLIP_MT_camera_presets, - CLIP_MT_track_color_presets, - CLIP_MT_tracking_settings_presets, + CLIP_PT_camera_presets, + CLIP_PT_track_color_presets, + CLIP_PT_tracking_settings_presets, CLIP_MT_track_color_specials, CLIP_MT_stabilize_2d_specials, CLIP_MT_stabilize_2d_rotation_specials, diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index e6f96d989c7..dd5ab03fcba 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -69,9 +69,7 @@ class CONSOLE_MT_console(Menu): layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class CONSOLE_MT_language(Menu): diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 731032bafa8..efd5e195fb8 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -19,11 +19,12 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu +from bpy.types import Header, Menu, Panel +from .space_time import * ####################################### -# DopeSheet Filtering +# DopeSheet Filtering - Header Buttons # used for DopeSheet, NLA, and Graph Editors def dopesheet_filter(layout, context, genericFiltersOnly=False): @@ -40,68 +41,153 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): row.prop(dopesheet, "show_only_errors", text="") if not genericFiltersOnly: - if bpy.data.groups: + if bpy.data.collections: row = layout.row(align=True) - row.prop(dopesheet, "show_only_group_objects", text="") - if dopesheet.show_only_group_objects: - row.prop(dopesheet, "filter_group", text="") + row.prop(dopesheet, "filter_collection", text="") if not is_nla: row = layout.row(align=True) - row.prop(dopesheet, "show_only_matching_fcurves", text="") - if dopesheet.show_only_matching_fcurves: - row.prop(dopesheet, "filter_fcurve_name", text="") - row.prop(dopesheet, "use_multi_word_filter", text="") + row.prop(dopesheet, "filter_fcurve_name", text="") else: row = layout.row(align=True) - row.prop(dopesheet, "use_filter_text", text="") - if dopesheet.use_filter_text: + row.prop(dopesheet, "filter_text", text="") + +####################################### +# Dopesheet Filtering Popovers + +# Generic Layout - Used as base for filtering popovers used in all animation editors +# Used for DopeSheet, NLA, and Graph Editors + + +class DopesheetFilterPopoverBase: + bl_region_type = 'HEADER' + bl_label = "Filters" + + # Generic = Affects all datatypes + # XXX: Perhaps we want these to stay in the header instead, for easy/fast access + @classmethod + def draw_generic_filters(cls, context, layout): + dopesheet = context.space_data.dopesheet + is_nla = context.area.type == 'NLA_EDITOR' + + col = layout.column(align=True) + col.prop(dopesheet, "show_only_selected", icon='NONE') + col.prop(dopesheet, "show_hidden", icon='NONE') + + if is_nla: + col.prop(dopesheet, "show_missing_nla", icon='NONE') + else: # graph and dopesheet editors - F-Curves and drivers only + col.prop(dopesheet, "show_only_errors", icon='NONE') + + # Name/Membership Filters + # XXX: Perhaps these should just stay in the headers (exclusively)? + @classmethod + def draw_search_filters(cls, context, layout, generic_filters_only=False): + dopesheet = context.space_data.dopesheet + is_nla = context.area.type == 'NLA_EDITOR' + + col = layout.column(align=True) + col.label("With Name:") + if not is_nla: + row = col.row(align=True) + row.prop(dopesheet, "filter_fcurve_name", text="") + else: + row = col.row(align=True) row.prop(dopesheet, "filter_text", text="") - row.prop(dopesheet, "use_multi_word_filter", text="") - if not genericFiltersOnly: - row = layout.row(align=True) - row.prop(dopesheet, "show_datablock_filters", text="Filters") - - if dopesheet.show_datablock_filters: - row.prop(dopesheet, "show_scenes", text="") - row.prop(dopesheet, "show_worlds", text="") - row.prop(dopesheet, "show_nodes", text="") - - row.prop(dopesheet, "show_transforms", text="") - - if bpy.data.meshes: - row.prop(dopesheet, "show_meshes", text="") - if bpy.data.shape_keys: - row.prop(dopesheet, "show_shapekeys", text="") - if bpy.data.meshes: - row.prop(dopesheet, "show_modifiers", text="") - if bpy.data.materials: - row.prop(dopesheet, "show_materials", text="") - if bpy.data.lamps: - row.prop(dopesheet, "show_lamps", text="") - if bpy.data.textures: - row.prop(dopesheet, "show_textures", text="") - if bpy.data.cameras: - row.prop(dopesheet, "show_cameras", text="") - if bpy.data.curves: - row.prop(dopesheet, "show_curves", text="") - if bpy.data.metaballs: - row.prop(dopesheet, "show_metaballs", text="") - if bpy.data.lattices: - row.prop(dopesheet, "show_lattices", text="") - if bpy.data.armatures: - row.prop(dopesheet, "show_armatures", text="") - if bpy.data.particles: - row.prop(dopesheet, "show_particles", text="") - if bpy.data.speakers: - row.prop(dopesheet, "show_speakers", text="") - if bpy.data.linestyles: - row.prop(dopesheet, "show_linestyles", text="") - if bpy.data.grease_pencil: - row.prop(dopesheet, "show_gpencil", text="") - - layout.prop(dopesheet, "use_datablock_sort", text="") + if (not generic_filters_only) and (bpy.data.collections): + col = layout.column(align=True) + col.label("In Collection:") + col.prop(dopesheet, "filter_collection", text="") + + # Standard = Present in all panels + @classmethod + def draw_standard_filters(cls, context, layout): + dopesheet = context.space_data.dopesheet + + # Object Data Filters + layout.label("Include Sub-Object Data:") + split = layout.split() + + # TODO: Add per-channel/axis convenience toggles? + col = split.column() + col.prop(dopesheet, "show_transforms", text="Transforms") + + col = split.column() + col.prop(dopesheet, "show_modifiers", text="Modifiers") + + layout.separator() + + # datablock filters + layout.label("Include From Types:") + flow = layout.grid_flow(row_major=True, columns=2, even_rows=False, align=False) + + flow.prop(dopesheet, "show_scenes", text="Scenes") + flow.prop(dopesheet, "show_worlds", text="Worlds") + flow.prop(dopesheet, "show_nodes", text="Node Trees") + + if bpy.data.armatures: + flow.prop(dopesheet, "show_armatures", text="Armatures") + if bpy.data.cameras: + flow.prop(dopesheet, "show_cameras", text="Cameras") + if bpy.data.grease_pencil: + flow.prop(dopesheet, "show_gpencil", text="Grease Pencil Objects") + if bpy.data.lights: + flow.prop(dopesheet, "show_lights", text="Lights") + if bpy.data.materials: + flow.prop(dopesheet, "show_materials", text="Materials") + if bpy.data.textures: + flow.prop(dopesheet, "show_textures", text="Textures") + if bpy.data.meshes: + flow.prop(dopesheet, "show_meshes", text="Meshes") + if bpy.data.shape_keys: + flow.prop(dopesheet, "show_shapekeys", text="Shape Keys") + if bpy.data.curves: + flow.prop(dopesheet, "show_curves", text="Curves") + if bpy.data.particles: + flow.prop(dopesheet, "show_particles", text="Particles") + if bpy.data.lattices: + flow.prop(dopesheet, "show_lattices", text="Lattices") + if bpy.data.linestyles: + flow.prop(dopesheet, "show_linestyles", text="Line Styles") + if bpy.data.metaballs: + flow.prop(dopesheet, "show_metaballs", text="Metas") + if bpy.data.speakers: + flow.prop(dopesheet, "show_speakers", text="Speakers") + + layout.separator() + + # performance-related options (users will mostly have these enabled) + col = layout.column(align=True) + col.label("Options:") + col.prop(dopesheet, "use_datablock_sort", icon='NONE') + + +# Popover for Dopesheet Editor(s) - Dopesheet, Action, Shapekey, GPencil, Mask, etc. +class DOPESHEET_PT_filters(DopesheetFilterPopoverBase, Panel): + bl_space_type = 'DOPESHEET_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Filters" + + def draw(self, context): + layout = self.layout + + dopesheet = context.space_data.dopesheet + ds_mode = context.space_data.mode + + layout.prop(dopesheet, "show_summary", text="Summary") + + DopesheetFilterPopoverBase.draw_generic_filters(context, layout) + + if ds_mode in {'DOPESHEET', 'ACTION', 'GPENCIL'}: + layout.separator() + generic_filters_only = ds_mode != 'DOPESHEET' + DopesheetFilterPopoverBase.draw_search_filters(context, layout, + generic_filters_only=generic_filters_only) + + if ds_mode == 'DOPESHEET': + layout.separator() + DopesheetFilterPopoverBase.draw_standard_filters(context, layout) ####################################### @@ -114,27 +200,49 @@ class DOPESHEET_HT_header(Header): layout = self.layout st = context.space_data - toolsettings = context.tool_settings row = layout.row(align=True) row.template_header() - DOPESHEET_MT_editor_menus.draw_collapsible(context, layout) + if st.mode == 'TIMELINE': + TIME_MT_editor_menus.draw_collapsible(context, layout) + TIME_HT_editor_buttons.draw_header(context, layout) + else: + layout.prop(st, "ui_mode", text="") - layout.prop(st, "mode", text="") + DOPESHEET_MT_editor_menus.draw_collapsible(context, layout) + DOPESHEET_HT_editor_buttons.draw_header(context, layout) + + +# Header for "normal" dopesheet editor modes (e.g. Dope Sheet, Action, Shape Keys, etc.) +class DOPESHEET_HT_editor_buttons(Header): + bl_idname = "DOPESHEET_HT_editor_buttons" + bl_space_type = 'DOPESHEET_EDITOR' + bl_label = "" + + def draw(self, context): + pass + + @staticmethod + def draw_header(context, layout): + st = context.space_data + toolsettings = context.tool_settings if st.mode in {'ACTION', 'SHAPEKEY'}: + # TODO: These buttons need some tidying up - Probably by using a popover, and bypassing the template_id() here row = layout.row(align=True) row.operator("action.layer_prev", text="", icon='TRIA_DOWN') row.operator("action.layer_next", text="", icon='TRIA_UP') - layout.template_ID(st, "action", new="action.new", unlink="action.unlink") - row = layout.row(align=True) row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN') row.operator("action.stash", text="Stash", icon='FREEZE') - layout.prop(st.dopesheet, "show_summary", text="Summary") + layout.separator_spacer() + + layout.template_ID(st, "action", new="action.new", unlink="action.unlink") + + layout.separator_spacer() if st.mode == 'DOPESHEET': dopesheet_filter(layout, context) @@ -152,26 +260,28 @@ class DOPESHEET_HT_header(Header): row.prop(st.dopesheet, "show_hidden", text="") row = layout.row(align=True) - row.prop(st.dopesheet, "use_filter_text", text="") - if st.dopesheet.use_filter_text: - row.prop(st.dopesheet, "filter_text", text="") - row.prop(st.dopesheet, "use_multi_word_filter", text="") + row.prop(st.dopesheet, "filter_text", text="") - row = layout.row(align=True) - row.prop(toolsettings, "use_proportional_action", - text="", icon_only=True) - if toolsettings.use_proportional_action: - row.prop(toolsettings, "proportional_edit_falloff", - text="", icon_only=True) + layout.popover( + panel="DOPESHEET_PT_filters", + text="", + icon='FILTER', + ) # Grease Pencil mode doesn't need snapping, as it's frame-aligned only if st.mode != 'GPENCIL': layout.prop(st, "auto_snap", text="") row = layout.row(align=True) + row.prop(toolsettings, "use_proportional_action", text="", icon_only=True) + sub = row.row(align=True) + sub.active = toolsettings.use_proportional_action + sub.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True) + + row = layout.row(align=True) row.operator("action.copy", text="", icon='COPYDOWN') row.operator("action.paste", text="", icon='PASTEDOWN') - if st.mode not in ('GPENCIL', 'MASK'): + if st.mode not in {'GPENCIL', 'MASK'}: row.operator("action.paste", text="", icon='PASTEFLIPDOWN').flipped = True @@ -212,6 +322,10 @@ class DOPESHEET_MT_view(Menu): layout.operator("action.properties", icon='MENU_PANEL') layout.separator() + layout.prop(st.dopesheet, "use_multi_word_filter", text="Multi-word Match Search") + + layout.separator() + layout.prop(st, "use_realtime_update") layout.prop(st, "show_frame_indicator") layout.prop(st, "show_sliders") @@ -233,9 +347,7 @@ class DOPESHEET_MT_view(Menu): layout.operator("action.view_frame") layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class DOPESHEET_MT_select(Menu): @@ -244,9 +356,9 @@ class DOPESHEET_MT_select(Menu): def draw(self, context): layout = self.layout - # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None - layout.operator("action.select_all_toggle").invert = False - layout.operator("action.select_all_toggle", text="Invert Selection").invert = True + layout.operator("action.select_all", text="All").action = 'SELECT' + layout.operator("action.select_all", text="None").action = 'DESELECT' + layout.operator("action.select_all", text="Invert").action = 'INVERT' layout.separator() layout.operator("action.select_border").axis_range = False @@ -449,8 +561,69 @@ class DOPESHEET_MT_delete(Menu): layout.operator("action.clean", text="Clean Channels").channels = True +class DOPESHEET_MT_specials(Menu): + bl_label = "Dope Sheet Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator("action.copy", text="Copy") + layout.operator("action.paste", text="Paste") + layout.operator("action.paste", text="Paste Flipped").flipped = True + + layout.separator() + + layout.operator_menu_enum("action.handle_type", "type", text="Handle Type") + layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode") + layout.operator_menu_enum("action.easing_type", "type", text="Easing Type") + + layout.separator() + + layout.operator("action.keyframe_insert").type = 'SEL' + layout.operator("action.duplicate_move") + layout.operator("action.delete") + + layout.separator() + + layout.operator_menu_enum("action.mirror", "type", text="Mirror") + layout.operator_menu_enum("action.snap", "type", text="Snap") + + +class DOPESHEET_MT_channel_specials(Menu): + bl_label = "Dope Sheet Channel Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE' + layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE' + layout.separator() + layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT' + layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT' + + layout.separator() + layout.operator("anim.channels_group") + layout.operator("anim.channels_ungroup") + + layout.separator() + layout.operator("anim.channels_editable_toggle") + layout.operator_menu_enum("action.extrapolation_type", "type", text="Extrapolation Mode") + + layout.separator() + layout.operator("anim.channels_expand") + layout.operator("anim.channels_collapse") + + layout.separator() + layout.operator_menu_enum("anim.channels_move", "direction", text="Move...") + + layout.separator() + + layout.operator("anim.channels_delete") + + classes = ( DOPESHEET_HT_header, + DOPESHEET_HT_editor_buttons, DOPESHEET_MT_editor_menus, DOPESHEET_MT_view, DOPESHEET_MT_select, @@ -461,6 +634,9 @@ classes = ( DOPESHEET_MT_gpencil_channel, DOPESHEET_MT_gpencil_frame, DOPESHEET_MT_delete, + DOPESHEET_MT_specials, + DOPESHEET_MT_channel_specials, + DOPESHEET_PT_filters, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 2d45d11b423..a85dd591b2f 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -18,7 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Panel, Menu +from bpy.types import Header, Panel, Menu, UIList class FILEBROWSER_HT_header(Header): @@ -33,8 +33,7 @@ class FILEBROWSER_HT_header(Header): if st.active_operator is None: layout.template_header() - row = layout.row() - row.separator() + layout.menu("FILEBROWSER_MT_view") row = layout.row(align=True) row.operator("file.previous", text="", icon='BACK') @@ -42,10 +41,8 @@ class FILEBROWSER_HT_header(Header): row.operator("file.parent", text="", icon='FILE_PARENT') row.operator("file.refresh", text="", icon='FILE_REFRESH') - layout.separator() layout.operator_context = 'EXEC_DEFAULT' layout.operator("file.directory_new", icon='NEWFOLDER', text="") - layout.separator() layout.operator_context = 'INVOKE_DEFAULT' @@ -53,20 +50,19 @@ class FILEBROWSER_HT_header(Header): if params: is_lib_browser = params.use_library_browsing - layout.prop(params, "recursion_level", text="") - layout.prop(params, "display_type", expand=True, text="") + layout.prop(params, "sort_method", expand=True, text="") + layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN') - layout.prop(params, "display_size", text="") + layout.separator_spacer() - layout.prop(params, "sort_method", expand=True, text="") + layout.template_running_jobs() - layout.prop(params, "show_hidden", text="", icon='FILE_HIDDEN') + if params: layout.prop(params, "use_filter", text="", icon='FILTER') row = layout.row(align=True) row.active = params.use_filter - row.prop(params, "use_filter_folder", text="") if params.filter_glob: @@ -92,10 +88,8 @@ class FILEBROWSER_HT_header(Header): row.separator() row.prop(params, "filter_search", text="", icon='VIEWZOOM') - layout.template_running_jobs() - -class FILEBROWSER_UL_dir(bpy.types.UIList): +class FILEBROWSER_UL_dir(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): direntry = item # space = context.space_data @@ -248,6 +242,22 @@ class FILEBROWSER_PT_advanced_filter(Panel): col.prop(params, "filter_id") +class FILEBROWSER_MT_view(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + st = context.space_data + params = st.params + + layout.prop_menu_enum(params, "display_size") + layout.prop_menu_enum(params, "recursion_level") + + layout.separator() + + layout.menu("INFO_MT_area") + + classes = ( FILEBROWSER_HT_header, FILEBROWSER_UL_dir, @@ -257,6 +267,7 @@ classes = ( FILEBROWSER_PT_bookmarks, FILEBROWSER_PT_recent_folders, FILEBROWSER_PT_advanced_filter, + FILEBROWSER_MT_view, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 5ed58a57e47..eacfb364130 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -19,15 +19,17 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu +from bpy.types import Header, Menu, Panel +from .space_dopesheet import ( + DopesheetFilterPopoverBase, + dopesheet_filter, +) class GRAPH_HT_header(Header): bl_space_type = 'GRAPH_EDITOR' def draw(self, context): - from .space_dopesheet import dopesheet_filter - layout = self.layout toolsettings = context.tool_settings @@ -36,11 +38,10 @@ class GRAPH_HT_header(Header): row = layout.row(align=True) row.template_header() - GRAPH_MT_editor_menus.draw_collapsible(context, layout) - - layout.prop(st, "mode", text="") + # Now a exposed as a sub-space type + # layout.prop(st, "mode", text="") - dopesheet_filter(layout, context) + GRAPH_MT_editor_menus.draw_collapsible(context, layout) row = layout.row(align=True) row.prop(st, "use_normalization", icon='NORMALIZE_FCURVES', text="Normalize", toggle=True) @@ -48,15 +49,30 @@ class GRAPH_HT_header(Header): sub.active = st.use_normalization sub.prop(st, "use_auto_normalization", icon='FILE_REFRESH', text="", toggle=True) + layout.separator_spacer() + + dopesheet_filter(layout, context) + row = layout.row(align=True) + if st.has_ghost_curves: + row.operator("graph.ghost_curves_clear", text="", icon='GHOST_DISABLED') + else: + row.operator("graph.ghost_curves_create", text="", icon='GHOST_ENABLED') - row.prop(toolsettings, "use_proportional_fcurve", - text="", icon_only=True) - if toolsettings.use_proportional_fcurve: - row.prop(toolsettings, "proportional_edit_falloff", - text="", icon_only=True) + layout.popover( + panel="GRAPH_PT_filters", + text="", + icon='FILTER', + ) layout.prop(st, "auto_snap", text="") + + row = layout.row(align=True) + row.prop(toolsettings, "use_proportional_fcurve", text="", icon_only=True) + sub = row.row(align=True) + sub.active = toolsettings.use_proportional_fcurve + sub.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True) + layout.prop(st, "pivot_point", icon_only=True) row = layout.row(align=True) @@ -64,11 +80,20 @@ class GRAPH_HT_header(Header): row.operator("graph.paste", text="", icon='PASTEDOWN') row.operator("graph.paste", text="", icon='PASTEFLIPDOWN').flipped = True - row = layout.row(align=True) - if st.has_ghost_curves: - row.operator("graph.ghost_curves_clear", text="", icon='GHOST_DISABLED') - else: - row.operator("graph.ghost_curves_create", text="", icon='GHOST_ENABLED') + +class GRAPH_PT_filters(DopesheetFilterPopoverBase, Panel): + bl_space_type = 'GRAPH_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Filters" + + def draw(self, context): + layout = self.layout + + DopesheetFilterPopoverBase.draw_generic_filters(context, layout) + layout.separator() + DopesheetFilterPopoverBase.draw_search_filters(context, layout) + layout.separator() + DopesheetFilterPopoverBase.draw_standard_filters(context, layout) class GRAPH_MT_editor_menus(Menu): @@ -129,9 +154,7 @@ class GRAPH_MT_view(Menu): layout.operator("graph.view_frame") layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class GRAPH_MT_select(Menu): @@ -140,11 +163,12 @@ class GRAPH_MT_select(Menu): def draw(self, context): layout = self.layout - # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None - layout.operator("graph.select_all_toggle").invert = False - layout.operator("graph.select_all_toggle", text="Invert Selection").invert = True + layout.operator("graph.select_all", text="All").action = 'SELECT' + layout.operator("graph.select_all", text="None").action = 'DESELECT' + layout.operator("graph.select_all", text="Invert").action = 'INVERT' layout.separator() + props = layout.operator("graph.select_border") props.axis_range = False props.include_handles = False @@ -302,6 +326,75 @@ class GRAPH_MT_delete(Menu): layout.operator("graph.clean", text="Clean Channels").channels = True +class GRAPH_MT_specials(Menu): + bl_label = "F-Curve Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator("graph.copy", text="Copy") + layout.operator("graph.paste", text="Paste") + layout.operator("graph.paste", text="Paste Flipped").flipped = True + + layout.separator() + + layout.operator_menu_enum("graph.handle_type", "type", text="Handle Type") + layout.operator_menu_enum("graph.interpolation_type", "type", text="Interpolation Mode") + layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type") + + layout.separator() + + layout.operator("graph.keyframe_insert").type = 'SEL' + layout.operator("graph.duplicate_move") + layout.operator("graph.delete") + + layout.separator() + + layout.operator_menu_enum("graph.mirror", "type", text="Mirror") + layout.operator_menu_enum("graph.snap", "type", text="Snap") + + +class GRAPH_MT_channel_specials(Menu): + bl_label = "F-Curve Channel Context Menu" + + def draw(self, context): + layout = self.layout + st = context.space_data + + layout.separator() + layout.operator("anim.channels_setting_enable", text="Mute Channels").type = 'MUTE' + layout.operator("anim.channels_setting_disable", text="Unmute Channels").type = 'MUTE' + layout.separator() + layout.operator("anim.channels_setting_enable", text="Protect Channels").type = 'PROTECT' + layout.operator("anim.channels_setting_disable", text="Unprotect Channels").type = 'PROTECT' + + layout.separator() + layout.operator("anim.channels_group") + layout.operator("anim.channels_ungroup") + + layout.separator() + layout.operator("anim.channels_editable_toggle") + layout.operator_menu_enum("graph.extrapolation_type", "type", text="Extrapolation Mode") + + layout.separator() + layout.operator("graph.hide", text="Hide Selected Curves").unselected = False + layout.operator("graph.hide", text="Hide Unselected Curves").unselected = True + layout.operator("graph.reveal") + + layout.separator() + layout.operator("anim.channels_expand") + layout.operator("anim.channels_collapse") + + layout.separator() + layout.operator_menu_enum("anim.channels_move", "direction", text="Move...") + + layout.separator() + + layout.operator("anim.channels_delete") + if st.mode == 'DRIVERS': + layout.operator("graph.driver_delete_invalid") + + classes = ( GRAPH_HT_header, GRAPH_MT_editor_menus, @@ -312,6 +405,9 @@ classes = ( GRAPH_MT_key, GRAPH_MT_key_transform, GRAPH_MT_delete, + GRAPH_MT_specials, + GRAPH_MT_channel_specials, + GRAPH_PT_filters, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 9a2215969cf..7a1d4117451 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -19,7 +19,7 @@ # <pep8 compliant> import bpy import math -from bpy.types import Header, Menu, Panel +from bpy.types import Header, Menu, Panel, UIList from .properties_paint_common import ( UnifiedPaintPanel, brush_texture_settings, @@ -28,12 +28,7 @@ from .properties_paint_common import ( ) from .properties_grease_pencil_common import ( GreasePencilDrawingToolsPanel, - GreasePencilStrokeEditPanel, - GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel, GreasePencilDataPanel, - GreasePencilPaletteColorPanel, ) from bpy.app.translations import pgettext_iface as iface_ @@ -130,9 +125,7 @@ class IMAGE_MT_view(Menu): layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class IMAGE_MT_select(Menu): @@ -141,14 +134,20 @@ class IMAGE_MT_select(Menu): def draw(self, context): layout = self.layout + layout.operator("uv.select_all", text="All").action = 'SELECT' + layout.operator("uv.select_all", text="None").action = 'DESELECT' + layout.operator("uv.select_all", text="Invert").action = 'INVERT' + + layout.separator() + layout.operator("uv.select_border").pinned = False layout.operator("uv.select_border", text="Border Select Pinned").pinned = True layout.operator("uv.circle_select") layout.separator() - layout.operator("uv.select_all").action = 'TOGGLE' - layout.operator("uv.select_all", text="Inverse").action = 'INVERT' + layout.operator("uv.select_less", text="Less") + layout.operator("uv.select_more", text="More") layout.separator() @@ -157,11 +156,6 @@ class IMAGE_MT_select(Menu): layout.separator() - layout.operator("uv.select_less", text="Less") - layout.operator("uv.select_more", text="More") - - layout.separator() - layout.operator("uv.select_split") @@ -192,30 +186,33 @@ class IMAGE_MT_image(Menu): sima = context.space_data ima = sima.image - - layout.operator("image.new") - layout.operator("image.open") - show_render = sima.show_render - layout.operator("image.read_renderlayers") + layout.operator("image.new", text="New") + layout.operator("image.open", text="Open...") - layout.operator("image.save_dirty", text="Save All Images") + layout.operator("image.read_viewlayers") if ima: if not show_render: - layout.operator("image.replace") - layout.operator("image.reload") + layout.operator("image.replace", text="Replace...") + layout.operator("image.reload", text="Reload") - layout.operator("image.save") - layout.operator("image.save_as") - layout.operator("image.save_as", text="Save a Copy").copy = True + layout.operator("image.external_edit", "Edit Externally") - if ima.source == 'SEQUENCE': - layout.operator("image.save_sequence") + layout.separator() - layout.operator("image.external_edit", "Edit Externally") + if ima: + layout.operator("image.save", text="Save") + layout.operator("image.save_as", text="Save As...") + layout.operator("image.save_as", text="Save a Copy...").copy = True + + if ima and ima.source == 'SEQUENCE': + layout.operator("image.save_sequence") + + layout.operator("image.save_dirty", text="Save All Images") + if ima: layout.separator() layout.menu("IMAGE_MT_image_invert") @@ -223,7 +220,7 @@ class IMAGE_MT_image(Menu): if not show_render: if not ima.packed_file: layout.separator() - layout.operator("image.pack") + layout.operator("image.pack", text="Pack") # only for dirty && specific image types, perhaps # this could be done in operator poll too @@ -428,6 +425,43 @@ class IMAGE_MT_uvs_select_mode(Menu): props.data_path = "tool_settings.uv_select_mode" +class IMAGE_MT_specials(Menu): + bl_label = "UV Context Menu" + + def draw(self, context): + layout = self.layout + + sima = context.space_data + + # UV Edit Mode + if sima.show_uvedit: + layout.operator("uv.unwrap") + layout.operator("uv.follow_active_quads") + + layout.separator() + + layout.operator("uv.pin").clear = False + layout.operator("uv.pin", text="Unpin").clear = True + + layout.separator() + + layout.operator("uv.weld") + layout.operator("uv.stitch") + + layout.separator() + + layout.operator_enum("uv.align", "axis") # W, 2/3/4 + + layout.separator() + + layout.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True + layout.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True + + layout.separator() + + layout.menu("IMAGE_MT_uvs_snap") + + class IMAGE_HT_header(Header): bl_space_type = 'IMAGE_EDITOR' @@ -447,20 +481,8 @@ class IMAGE_HT_header(Header): row = layout.row(align=True) row.template_header() - MASK_MT_editor_menus.draw_collapsible(context, layout) - - layout.template_ID(sima, "image", new="image.new", open="image.open") - if not show_render: - layout.prop(sima, "use_image_pin", text="") - layout.prop(sima, "mode", text="") - if show_maskedit: - row = layout.row() - row.template_ID(sima, "mask", new="mask.new") - - layout.prop(sima, "pivot_point", icon_only=True) - # uv editing if show_uvedit: uvedit = sima.uv_editor @@ -473,19 +495,45 @@ class IMAGE_HT_header(Header): layout.prop(toolsettings, "uv_select_mode", text="", expand=True) layout.prop(uvedit, "sticky_select_mode", icon_only=True) - row = layout.row(align=True) - row.prop(toolsettings, "proportional_edit", icon_only=True) - if toolsettings.proportional_edit != 'DISABLED': - row.prop(toolsettings, "proportional_edit_falloff", icon_only=True) + MASK_MT_editor_menus.draw_collapsible(context, layout) + + layout.separator_spacer() + + layout.template_ID(sima, "image", new="image.new", open="image.open") + + if show_maskedit: + row = layout.row() + row.template_ID(sima, "mask", new="mask.new") + + layout.separator_spacer() + if show_uvedit or show_maskedit or mode == 'PAINT': + layout.prop(sima, "use_realtime_update", icon_only=True, icon='FILE_REFRESH') + + if not show_render: + layout.prop(sima, "use_image_pin", text="") + + if show_uvedit: + uvedit = sima.uv_editor + + mesh = context.edit_object.data + layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="") + + # Snap row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") row.prop(toolsettings, "snap_uv_element", icon_only=True) if toolsettings.snap_uv_element != 'INCREMENT': row.prop(toolsettings, "snap_target", text="") - mesh = context.edit_object.data - layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="") + row = layout.row(align=True) + row.prop(toolsettings, "proportional_edit", icon_only=True) + # if toolsettings.proportional_edit != 'DISABLED': + sub = row.row(align=True) + sub.active = toolsettings.proportional_edit != 'DISABLED' + sub.prop(toolsettings, "proportional_edit_falloff", icon_only=True) + + layout.prop(sima, "pivot_point", icon_only=True) if ima: if ima.is_stereo_3d: @@ -505,9 +553,6 @@ class IMAGE_HT_header(Header): if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}: row.operator("image.play_composite", icon='PLAY') - if show_uvedit or show_maskedit or mode == 'PAINT': - layout.prop(sima, "use_realtime_update", icon_only=True, icon='LOCKED') - class MASK_MT_editor_menus(Menu): bl_idname = "MASK_MT_editor_menus" @@ -619,50 +664,6 @@ class IMAGE_PT_image_properties(Panel): layout.template_image(sima, "image", iuser, multiview=True) -class IMAGE_PT_game_properties(Panel): - bl_space_type = 'IMAGE_EDITOR' - bl_region_type = 'UI' - bl_label = "Game Properties" - - @classmethod - def poll(cls, context): - sima = context.space_data - # display even when not in game mode because these settings effect the 3d view - return (sima and sima.image and not sima.show_maskedit) # and (rd.engine == 'BLENDER_GAME') - - def draw(self, context): - layout = self.layout - - sima = context.space_data - ima = sima.image - - split = layout.split() - col = split.column() - col.prop(ima, "use_animation") - sub = col.column(align=True) - sub.active = ima.use_animation - sub.prop(ima, "frame_start", text="Start") - sub.prop(ima, "frame_end", text="End") - sub.prop(ima, "fps", text="Speed") - - col = split.column() - col.prop(ima, "use_tiles") - sub = col.column(align=True) - sub.active = ima.use_tiles or ima.use_animation - sub.prop(ima, "tiles_x", text="X") - sub.prop(ima, "tiles_y", text="Y") - - split = layout.split() - col = split.column() - col.label(text="Clamp:") - col.prop(ima, "use_clamp_x", text="X") - col.prop(ima, "use_clamp_y", text="Y") - - col = split.column() - col.label(text="Mapping:") - col.prop(ima, "mapping", expand=True) - - class IMAGE_PT_view_properties(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' @@ -694,11 +695,11 @@ class IMAGE_PT_view_properties(Panel): col.label(text="Coordinates:") col.prop(sima, "show_repeat", text="Repeat") if show_uvedit: - col.prop(uvedit, "show_normalized_coords", text="Normalized") + col.prop(uvedit, "show_pixel_coords", text="Pixel") elif show_uvedit: col.label(text="Coordinates:") - col.prop(uvedit, "show_normalized_coords", text="Normalized") + col.prop(uvedit, "show_pixel_coords", text="Pixel") if show_uvedit or show_maskedit: col = layout.column() @@ -730,10 +731,41 @@ class IMAGE_PT_view_properties(Panel): row.active = uvedit.show_other_objects row.prop(uvedit, "other_uv_filter", text="Filter") - if show_render and ima: - layout.separator() - render_slot = ima.render_slots.active - layout.prop(render_slot, "name", text="Slot Name") + +class IMAGE_UL_render_slots(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + slot = item + layout.prop(slot, "name", text="", emboss=False) + + +class IMAGE_PT_render_slots(Panel): + bl_space_type = 'IMAGE_EDITOR' + bl_region_type = 'UI' + bl_label = "Render Slots" + + @classmethod + def poll(cls, context): + sima = context.space_data + return (sima and sima.image and sima.show_render) + + def draw(self, context): + layout = self.layout + + sima = context.space_data + ima = sima.image + + row = layout.row() + + col = row.column() + col.template_list("IMAGE_UL_render_slots", "render_slots", ima, "render_slots", ima.render_slots, "active_index", rows=3) + + col = row.column(align=True) + col.operator("image.add_render_slot", icon='ZOOMIN', text="") + col.operator("image.remove_render_slot", icon='ZOOMOUT', text="") + + col.separator() + + col.operator("image.clear_render_slot", icon='X', text="") class IMAGE_PT_tools_transform_uvs(Panel, UVToolsPanel): @@ -1309,38 +1341,12 @@ class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel): # NOTE: this is just a wrapper around the generic GP Panel - -# Grease Pencil palette colors -class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - - # Grease Pencil drawing tools -class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - - -# Grease Pencil stroke editing tools -class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - -# Grease Pencil stroke sculpting tools -class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - -# Grease Pencil drawing brushes -class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'IMAGE_EDITOR' - - -# Grease Pencil drawing curves -class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): +class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): bl_space_type = 'IMAGE_EDITOR' + bl_region_type = 'TOOLS' classes = ( @@ -1357,6 +1363,7 @@ classes = ( IMAGE_MT_uvs_mirror, IMAGE_MT_uvs_weldalign, IMAGE_MT_uvs_select_mode, + IMAGE_MT_specials, IMAGE_HT_header, MASK_MT_editor_menus, IMAGE_PT_mask, @@ -1366,7 +1373,8 @@ classes = ( IMAGE_PT_active_mask_spline, IMAGE_PT_active_mask_point, IMAGE_PT_image_properties, - IMAGE_PT_game_properties, + IMAGE_UL_render_slots, + IMAGE_PT_render_slots, IMAGE_PT_view_properties, IMAGE_PT_tools_transform_uvs, IMAGE_PT_tools_align_uvs, @@ -1391,12 +1399,7 @@ classes = ( IMAGE_PT_sample_line, IMAGE_PT_scope_sample, IMAGE_PT_grease_pencil, - IMAGE_PT_grease_pencil_palettecolor, IMAGE_PT_tools_grease_pencil_draw, - IMAGE_PT_tools_grease_pencil_edit, - IMAGE_PT_tools_grease_pencil_sculpt, - IMAGE_PT_tools_grease_pencil_brush, - IMAGE_PT_tools_grease_pencil_brushcurves, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index edae5e2f452..e5ef5f9a0da 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -26,346 +26,29 @@ class INFO_HT_header(Header): def draw(self, context): layout = self.layout + layout.template_header() - window = context.window - scene = context.scene - rd = scene.render + # Empty for now until info editor gets turned into log editor + pass - row = layout.row(align=True) - row.template_header() - INFO_MT_editor_menus.draw_collapsible(context, layout) - - if window.screen.show_fullscreen: - layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous") - layout.separator() - else: - layout.template_ID(context.window, "screen", new="screen.new", unlink="screen.delete") - layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete") - - layout.separator() - - if rd.has_multiple_engines: - layout.prop(rd, "engine", text="") - - layout.separator() - - layout.template_running_jobs() - - layout.template_reports_banner() - - row = layout.row(align=True) - - if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False: - row.label("Auto-run disabled", icon='ERROR') - if bpy.data.is_saved: - props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted") - props.use_scripts = True - - row.operator("script.autoexec_warn_clear", text="Ignore") - - # include last so text doesn't push buttons out of the header - row.label(bpy.app.autoexec_fail_message) - return - - row.operator("wm.splash", text="", icon='BLENDER', emboss=False) - row.label(text=scene.statistics(), translate=False) - - -class INFO_MT_editor_menus(Menu): - bl_idname = "INFO_MT_editor_menus" - bl_label = "" - - def draw(self, context): - self.draw_menus(self.layout, context) - - @staticmethod - def draw_menus(layout, context): - scene = context.scene - rd = scene.render - - layout.menu("INFO_MT_file") - - if rd.use_game_engine: - layout.menu("INFO_MT_game") - else: - layout.menu("INFO_MT_render") - - layout.menu("INFO_MT_window") - layout.menu("INFO_MT_help") - - -class INFO_MT_file(Menu): - bl_label = "File" - - def draw(self, context): - layout = self.layout - - layout.operator_context = 'INVOKE_AREA' - layout.operator("wm.read_homefile", text="New", icon='NEW') - layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER') - layout.menu("INFO_MT_file_open_recent", icon='OPEN_RECENT') - layout.operator("wm.revert_mainfile", icon='FILE_REFRESH') - layout.operator("wm.recover_last_session", icon='RECOVER_LAST') - layout.operator("wm.recover_auto_save", text="Recover Auto Save...", icon='RECOVER_AUTO') - - layout.separator() - - layout.operator_context = 'EXEC_AREA' if context.blend_data.is_saved else 'INVOKE_AREA' - layout.operator("wm.save_mainfile", text="Save", icon='FILE_TICK') - - layout.operator_context = 'INVOKE_AREA' - layout.operator("wm.save_as_mainfile", text="Save As...", icon='SAVE_AS') - layout.operator_context = 'INVOKE_AREA' - layout.operator("wm.save_as_mainfile", text="Save Copy...", icon='SAVE_COPY').copy = True - - layout.separator() - - layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES') - - layout.operator_context = 'INVOKE_AREA' - layout.operator("wm.save_homefile", icon='SAVE_PREFS') - layout.operator("wm.read_factory_settings", icon='LOAD_FACTORY') - - if any(bpy.utils.app_template_paths()): - app_template = context.user_preferences.app_template - if app_template: - layout.operator( - "wm.read_factory_settings", - text="Load Factory Template Settings", - icon='LOAD_FACTORY', - ).app_template = app_template - del app_template - - layout.menu("USERPREF_MT_app_templates", icon='FILE_BLEND') - - layout.separator() - - layout.operator_context = 'INVOKE_AREA' - layout.operator("wm.link", text="Link", icon='LINK_BLEND') - layout.operator("wm.append", text="Append", icon='APPEND_BLEND') - layout.menu("INFO_MT_file_previews") - - layout.separator() - - layout.menu("INFO_MT_file_import", icon='IMPORT') - layout.menu("INFO_MT_file_export", icon='EXPORT') - - layout.separator() - - layout.menu("INFO_MT_file_external_data", icon='EXTERNAL_DATA') - layout.operator("wm.blend_strings_utf8_validate", icon='FILE_BLEND') - - layout.separator() - - layout.operator_context = 'EXEC_AREA' - if bpy.data.is_dirty and context.user_preferences.view.use_quit_dialog: - layout.operator_context = 'INVOKE_SCREEN' # quit dialog - layout.operator("wm.quit_blender", text="Quit", icon='QUIT') - - -class INFO_MT_file_import(Menu): - bl_idname = "INFO_MT_file_import" - bl_label = "Import" - - def draw(self, context): - if bpy.app.build_options.collada: - self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)") - if bpy.app.build_options.alembic: - self.layout.operator("wm.alembic_import", text="Alembic (.abc)") - - -class INFO_MT_file_export(Menu): - bl_idname = "INFO_MT_file_export" - bl_label = "Export" - - def draw(self, context): - if bpy.app.build_options.collada: - self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)") - if bpy.app.build_options.alembic: - self.layout.operator("wm.alembic_export", text="Alembic (.abc)") - - -class INFO_MT_file_external_data(Menu): - bl_label = "External Data" +# Not really info, just add to re-usable location. +class INFO_MT_area(Menu): + bl_label = "Area" def draw(self, context): layout = self.layout - icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT' - layout.operator("file.autopack_toggle", icon=icon) - - layout.separator() - - pack_all = layout.row() - pack_all.operator("file.pack_all") - pack_all.active = not bpy.data.use_autopack - - unpack_all = layout.row() - unpack_all.operator("file.unpack_all") - unpack_all.active = not bpy.data.use_autopack - - layout.separator() - - layout.operator("file.make_paths_relative") - layout.operator("file.make_paths_absolute") - layout.operator("file.report_missing_files") - layout.operator("file.find_missing_files") - - -class INFO_MT_file_previews(Menu): - bl_label = "Data Previews" - - def draw(self, context): - layout = self.layout - - layout.operator("wm.previews_ensure") - layout.operator("wm.previews_batch_generate") - - layout.separator() - - layout.operator("wm.previews_clear") - layout.operator("wm.previews_batch_clear") - - -class INFO_MT_game(Menu): - bl_label = "Game" - - def draw(self, context): - layout = self.layout - - gs = context.scene.game_settings - - layout.operator("view3d.game_start") - - layout.separator() - - layout.prop(gs, "show_debug_properties") - layout.prop(gs, "show_framerate_profile") - layout.prop(gs, "show_physics_visualization") - layout.prop(gs, "use_deprecation_warnings") - layout.prop(gs, "use_animation_record") - layout.separator() - layout.prop(gs, "use_auto_start") - - -class INFO_MT_render(Menu): - bl_label = "Render" - - def draw(self, context): - layout = self.layout - - layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True - props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION') - props.animation = True - props.use_viewport = True - - layout.separator() - - layout.operator("render.opengl", text="OpenGL Render Image") - layout.operator("render.opengl", text="OpenGL Render Animation").animation = True - layout.menu("INFO_MT_opengl_render") - - layout.separator() - - layout.operator("render.view_show") - layout.operator("render.play_rendered_anim", icon='PLAY') - - -class INFO_MT_opengl_render(Menu): - bl_label = "OpenGL Render Options" - - def draw(self, context): - layout = self.layout - - rd = context.scene.render - layout.prop(rd, "use_antialiasing") - layout.prop(rd, "use_full_sample") - - layout.prop_menu_enum(rd, "antialiasing_samples") - layout.prop_menu_enum(rd, "alpha_mode") - - -class INFO_MT_window(Menu): - bl_label = "Window" - - def draw(self, context): - import sys - - layout = self.layout - - layout.operator("wm.window_duplicate") - layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER') - - layout.separator() - - layout.operator("screen.screenshot") - - if sys.platform[:3] == "win": - layout.separator() - layout.operator("wm.console_toggle", icon='CONSOLE') - - if context.scene.render.use_multiview: - layout.separator() - layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO') - - -class INFO_MT_help(Menu): - bl_label = "Help" - - def draw(self, context): - layout = self.layout - - layout.operator( - "wm.url_open", text="Manual", icon='HELP', - ).url = "https://docs.blender.org/manual/en/dev/" - layout.operator( - "wm.url_open", text="Release Log", icon='URL', - ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2] - layout.separator() - - layout.operator( - "wm.url_open", text="Blender Website", icon='URL', - ).url = "https://www.blender.org" - layout.operator( - "wm.url_open", text="Blender Store", icon='URL', - ).url = "https://store.blender.org" - layout.operator( - "wm.url_open", text="Developer Community", icon='URL', - ).url = "https://www.blender.org/get-involved/" - layout.operator( - "wm.url_open", text="User Community", icon='URL', - ).url = "https://www.blender.org/support/user-community" - layout.separator() - layout.operator( - "wm.url_open", text="Report a Bug", icon='URL', - ).url = "https://developer.blender.org/maniphest/task/edit/form/1" - layout.separator() - - layout.operator( - "wm.url_open", text="Python API Reference", icon='URL', - ).url = bpy.types.WM_OT_doc_view._prefix - - layout.operator("wm.operator_cheat_sheet", icon='TEXT') - layout.operator("wm.sysinfo", icon='TEXT') - layout.separator() - - layout.operator("wm.splash", icon='BLENDER') + layout.operator("screen.area_dupli") + if context.space_data.type == 'VIEW_3D': + layout.operator("screen.region_quadview") + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True classes = ( INFO_HT_header, - INFO_MT_editor_menus, - INFO_MT_file, - INFO_MT_file_import, - INFO_MT_file_export, - INFO_MT_file_external_data, - INFO_MT_file_previews, - INFO_MT_game, - INFO_MT_render, - INFO_MT_opengl_render, - INFO_MT_window, - INFO_MT_help, + INFO_MT_area, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py deleted file mode 100644 index b552181f491..00000000000 --- a/release/scripts/startup/bl_ui/space_logic.py +++ /dev/null @@ -1,145 +0,0 @@ -# ##### 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> -import bpy -from bpy.types import Header, Menu, Panel - - -class LOGIC_PT_properties(Panel): - bl_space_type = 'LOGIC_EDITOR' - bl_region_type = 'UI' - bl_label = "Properties" - - @classmethod - def poll(cls, context): - ob = context.active_object - return ob and ob.game - - def draw(self, context): - layout = self.layout - - ob = context.active_object - game = ob.game - is_font = (ob.type == 'FONT') - - if is_font: - prop_index = game.properties.find("Text") - if prop_index != -1: - layout.operator("object.game_property_remove", text="Remove Text Game Property", icon='X').index = prop_index - row = layout.row() - sub = row.row() - sub.enabled = 0 - prop = game.properties[prop_index] - sub.prop(prop, "name", text="") - row.prop(prop, "type", text="") - # get the property from the body, not the game property - # note, don't do this - it's too slow and body can potentially be a really long string. - #~ row.prop(ob.data, "body", text="") - row.label("See Text Object") - else: - props = layout.operator("object.game_property_new", text="Add Text Game Property", icon='ZOOMIN') - props.name = "Text" - props.type = 'STRING' - - props = layout.operator("object.game_property_new", text="Add Game Property", icon='ZOOMIN') - props.name = "" - - for i, prop in enumerate(game.properties): - - if is_font and i == prop_index: - continue - - box = layout.box() - row = box.row() - row.prop(prop, "name", text="") - row.prop(prop, "type", text="") - row.prop(prop, "value", text="") - row.prop(prop, "show_debug", text="", toggle=True, icon='INFO') - sub = row.row(align=True) - props = sub.operator("object.game_property_move", text="", icon='TRIA_UP') - props.index = i - props.direction = 'UP' - props = sub.operator("object.game_property_move", text="", icon='TRIA_DOWN') - props.index = i - props.direction = 'DOWN' - row.operator("object.game_property_remove", text="", icon='X', emboss=False).index = i - - -class LOGIC_MT_logicbricks_add(Menu): - bl_label = "Add" - - def draw(self, context): - layout = self.layout - - layout.operator_menu_enum("logic.sensor_add", "type", text="Sensor") - layout.operator_menu_enum("logic.controller_add", "type", text="Controller") - layout.operator_menu_enum("logic.actuator_add", "type", text="Actuator") - - -class LOGIC_HT_header(Header): - bl_space_type = 'LOGIC_EDITOR' - - def draw(self, context): - layout = self.layout.row(align=True) - - layout.template_header() - - LOGIC_MT_editor_menus.draw_collapsible(context, layout) - - -class LOGIC_MT_editor_menus(Menu): - bl_idname = "LOGIC_MT_editor_menus" - bl_label = "" - - def draw(self, context): - self.draw_menus(self.layout, context) - - @staticmethod - def draw_menus(layout, context): - layout.menu("LOGIC_MT_view") - layout.menu("LOGIC_MT_logicbricks_add") - - -class LOGIC_MT_view(Menu): - bl_label = "View" - - def draw(self, context): - layout = self.layout - - layout.operator("logic.properties", icon='MENU_PANEL') - - layout.separator() - - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True - - -classes = ( - LOGIC_PT_properties, - LOGIC_MT_logicbricks_add, - LOGIC_HT_header, - LOGIC_MT_editor_menus, - LOGIC_MT_view, -) - -if __name__ == "__main__": # only for live edit. - from bpy.utils import register_class - for cls in classes: - register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 8a933570c5e..4e20001b133 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -19,15 +19,17 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu +from bpy.types import Header, Menu, Panel +from .space_dopesheet import ( + DopesheetFilterPopoverBase, + dopesheet_filter, +) class NLA_HT_header(Header): bl_space_type = 'NLA_EDITOR' def draw(self, context): - from .space_dopesheet import dopesheet_filter - layout = self.layout st = context.space_data @@ -37,11 +39,34 @@ class NLA_HT_header(Header): NLA_MT_editor_menus.draw_collapsible(context, layout) + layout.separator_spacer() + dopesheet_filter(layout, context) + layout.popover( + panel="NLA_PT_filters", + text="", + icon='FILTER', + ) + layout.prop(st, "auto_snap", text="") +class NLA_PT_filters(DopesheetFilterPopoverBase, Panel): + bl_space_type = 'NLA_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Filters" + + def draw(self, context): + layout = self.layout + + DopesheetFilterPopoverBase.draw_generic_filters(context, layout) + layout.separator() + DopesheetFilterPopoverBase.draw_search_filters(context, layout) + layout.separator() + DopesheetFilterPopoverBase.draw_standard_filters(context, layout) + + class NLA_MT_editor_menus(Menu): bl_idname = "NLA_MT_editor_menus" bl_label = "" @@ -90,9 +115,7 @@ class NLA_MT_view(Menu): layout.operator("nla.view_frame") layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class NLA_MT_select(Menu): @@ -101,9 +124,9 @@ class NLA_MT_select(Menu): def draw(self, context): layout = self.layout - # This is a bit misleading as the operator's default text is "Select All" while it actually *toggles* All/None - layout.operator("nla.select_all_toggle").invert = False - layout.operator("nla.select_all_toggle", text="Invert Selection").invert = True + layout.operator("nla.select_all", text="All").action = 'SELECT' + layout.operator("nla.select_all", text="None").action = 'DESELECT' + layout.operator("nla.select_all", text="Invert").action = 'INVERT' layout.separator() layout.operator("nla.select_border").axis_range = False @@ -219,6 +242,7 @@ classes = ( NLA_MT_marker, NLA_MT_add, NLA_MT_edit_transform, + NLA_PT_filters, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index c2735998d2c..43a124cd48f 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -21,15 +21,11 @@ import bpy import nodeitems_utils from bpy.types import Header, Menu, Panel from bpy.app.translations import pgettext_iface as iface_ +from bl_operators.presets import PresetMenu from .properties_grease_pencil_common import ( GreasePencilDrawingToolsPanel, - GreasePencilStrokeEditPanel, - GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel, GreasePencilDataPanel, - GreasePencilPaletteColorPanel, - GreasePencilToolsPanel + GreasePencilToolsPanel, ) @@ -48,78 +44,107 @@ class NODE_HT_header(Header): row = layout.row(align=True) row.template_header() - NODE_MT_editor_menus.draw_collapsible(context, layout) - - layout.prop(snode, "tree_type", text="", expand=True) + # Now expanded via the 'ui_type' + # layout.prop(snode, "tree_type", text="") if snode.tree_type == 'ShaderNodeTree': - if scene.render.use_shading_nodes: - layout.prop(snode, "shader_type", text="", expand=True) + layout.prop(snode, "shader_type", text="") ob = context.object - if (not scene.render.use_shading_nodes or snode.shader_type == 'OBJECT') and ob: + if snode.shader_type == 'OBJECT' and ob: + + NODE_MT_editor_menus.draw_collapsible(context, layout) + + # No shader nodes for Eevee lamps + if snode_id and not (context.engine == 'BLENDER_EEVEE' and ob.type == 'LIGHT'): + row = layout.row() + row.prop(snode_id, "use_nodes") + + layout.separator_spacer() + row = layout.row() # disable material slot buttons when pinned, cannot find correct slot within id_from (#36589) row.enabled = not snode.pin # Show material.new when no active ID/slot exists if not id_from and ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'METABALL'}: row.template_ID(ob, "active_material", new="material.new") - # Material ID, but not for Lamps - if id_from and ob.type != 'LAMP': + # Material ID, but not for Lights + if id_from and ob.type != 'LIGHT': row.template_ID(id_from, "active_material", new="material.new") - # Don't show "Use Nodes" Button when Engine is BI for Lamps - if snode_id and not (scene.render.use_shading_nodes == 0 and ob.type == 'LAMP'): - layout.prop(snode_id, "use_nodes") + if snode.shader_type == 'WORLD': + NODE_MT_editor_menus.draw_collapsible(context, layout) + + if snode_id: + row = layout.row() + row.prop(snode_id, "use_nodes") + + layout.separator_spacer() - if scene.render.use_shading_nodes and snode.shader_type == 'WORLD': row = layout.row() row.enabled = not snode.pin row.template_ID(scene, "world", new="world.new") - if snode_id: - row.prop(snode_id, "use_nodes") - if scene.render.use_shading_nodes and snode.shader_type == 'LINESTYLE': - rl = context.scene.render.layers.active - lineset = rl.freestyle_settings.linesets.active + if snode.shader_type == 'LINESTYLE': + view_layer = context.view_layer + lineset = view_layer.freestyle_settings.linesets.active + if lineset is not None: + NODE_MT_editor_menus.draw_collapsible(context, layout) + + if snode_id: + row = layout.row() + row.prop(snode_id, "use_nodes") + + layout.separator_spacer() + row = layout.row() row.enabled = not snode.pin row.template_ID(lineset, "linestyle", new="scene.freestyle_linestyle_new") - if snode_id: - row.prop(snode_id, "use_nodes") elif snode.tree_type == 'TextureNodeTree': - layout.prop(snode, "texture_type", text="", expand=True) + layout.prop(snode, "texture_type", text="") + + NODE_MT_editor_menus.draw_collapsible(context, layout) + + if snode_id: + layout.prop(snode_id, "use_nodes") + + layout.separator_spacer() if id_from: if snode.texture_type == 'BRUSH': layout.template_ID(id_from, "texture", new="texture.new") else: layout.template_ID(id_from, "active_texture", new="texture.new") - if snode_id: - layout.prop(snode_id, "use_nodes") elif snode.tree_type == 'CompositorNodeTree': + + NODE_MT_editor_menus.draw_collapsible(context, layout) + if snode_id: layout.prop(snode_id, "use_nodes") + + layout.prop(snode, "use_auto_render") layout.prop(snode, "show_backdrop") if snode.show_backdrop: row = layout.row(align=True) row.prop(snode, "backdrop_channels", text="", expand=True) - layout.prop(snode, "use_auto_render") else: # Custom node tree is edited as independent ID block + NODE_MT_editor_menus.draw_collapsible(context, layout) + + layout.separator_spacer() + layout.template_ID(snode, "node_tree", new="node.new_node_tree") - layout.prop(snode, "pin", text="") - layout.operator("node.tree_path_parent", text="", icon='FILE_PARENT') + layout.separator_spacer() - layout.separator() + layout.template_running_jobs() - # Auto-offset nodes (called "insert_offset" in code) - layout.prop(snode, "use_insert_offset", text="") + layout.prop(snode, "pin", text="") + layout.operator("node.tree_path_parent", text="", icon='FILE_PARENT') # Snap row = layout.row(align=True) @@ -132,8 +157,6 @@ class NODE_HT_header(Header): row.operator("node.clipboard_copy", text="", icon='COPYDOWN') row.operator("node.clipboard_paste", text="", icon='PASTEDOWN') - layout.template_running_jobs() - class NODE_MT_editor_menus(Menu): bl_idname = "NODE_MT_editor_menus" @@ -171,11 +194,18 @@ class NODE_MT_view(Menu): def draw(self, context): layout = self.layout + snode = context.space_data + layout.operator("node.properties", icon='MENU_PANEL') layout.operator("node.toolbar", icon='MENU_PANEL') layout.separator() + # Auto-offset nodes (called "insert_offset" in code) + layout.prop(snode, "use_insert_offset") + + layout.separator() + layout.operator("view2d.zoom_in") layout.operator("view2d.zoom_out") @@ -194,9 +224,7 @@ class NODE_MT_view(Menu): layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class NODE_MT_select(Menu): @@ -271,16 +299,16 @@ class NODE_MT_node(Menu): layout.separator() - layout.operator("node.read_renderlayers") + layout.operator("node.read_viewlayers") layout.operator("node.read_fullsamplelayers") -class NODE_MT_node_color_presets(Menu): +class NODE_PT_node_color_presets(PresetMenu): """Predefined node color""" bl_label = "Color Presets" preset_subdir = "node_color" preset_operator = "script.execute_preset" - draw = Menu.draw_preset + preset_add_operator = "node.node_color_preset_add" class NODE_MT_node_color_specials(Menu): @@ -292,11 +320,45 @@ class NODE_MT_node_color_specials(Menu): layout.operator("node.node_copy_color", icon='COPY_ID') +class NODE_MT_specials(Menu): + bl_label = "Node Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_DEFAULT' + layout.operator("node.duplicate_move") + layout.operator("node.delete") + layout.operator_context = 'EXEC_DEFAULT' + + layout.operator("node.delete_reconnect") + + layout.separator() + + layout.operator("node.link_make").replace = False + layout.operator("node.link_make", text="Make and Replace Links").replace = True + layout.operator("node.links_detach") + + layout.separator() + + layout.operator("node.group_make", text="Group") + layout.operator("node.group_ungroup", text="Ungroup") + layout.operator("node.group_edit").exit = False + + layout.separator() + + layout.operator("node.hide_toggle") + layout.operator("node.mute_toggle") + layout.operator("node.preview_toggle") + layout.operator("node.hide_socket_toggle") + layout.operator("node.options_toggle") + layout.operator("node.collapse_hide_unused_toggle") + + class NODE_PT_active_node_generic(Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' bl_label = "Node" -# bl_options = {'HIDE_HEADER'} @classmethod def poll(cls, context): @@ -315,6 +377,7 @@ class NODE_PT_active_node_color(Panel): bl_region_type = 'UI' bl_label = "Color" bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'NODE_PT_active_node_generic' @classmethod def poll(cls, context): @@ -324,6 +387,9 @@ class NODE_PT_active_node_color(Panel): node = context.active_node self.layout.prop(node, "use_custom_color", text="") + def draw_header_preset(self, context): + NODE_PT_node_color_presets.draw_panel_header(self.layout) + def draw(self, context): layout = self.layout node = context.active_node @@ -331,19 +397,16 @@ class NODE_PT_active_node_color(Panel): layout.enabled = node.use_custom_color row = layout.row() - col = row.column() - col.menu("NODE_MT_node_color_presets") - col.prop(node, "color", text="") - col = row.column(align=True) - col.operator("node.node_color_preset_add", text="", icon='ZOOMIN').remove_active = False - col.operator("node.node_color_preset_add", text="", icon='ZOOMOUT').remove_active = True - col.menu("NODE_MT_node_color_specials", text="", icon='DOWNARROW_HLT') + row.prop(node, "color", text="") + row.menu("NODE_MT_node_color_specials", text="", icon='DOWNARROW_HLT') class NODE_PT_active_node_properties(Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' bl_label = "Properties" + bl_options = {'DEFAULT_CLOSED'} + bl_parent_id = 'NODE_PT_active_node_generic' @classmethod def poll(cls, context): @@ -387,19 +450,22 @@ class NODE_PT_backdrop(Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True snode = context.space_data layout.active = snode.show_backdrop - layout.prop(snode, "backdrop_channels", text="") - layout.prop(snode, "backdrop_zoom", text="Zoom") - col = layout.column(align=True) - col.label(text="Offset:") - col.prop(snode, "backdrop_x", text="X") - col.prop(snode, "backdrop_y", text="Y") - col.operator("node.backimage_move", text="Move") + col = layout.column() + + col.prop(snode, "backdrop_channels", text="Channels") + col.prop(snode, "backdrop_zoom", text="Zoom") - layout.operator("node.backimage_fit", text="Fit") + col.prop(snode, "backdrop_offset", text="Offset") + + col.separator() + + col.operator("node.backimage_move", text="Move") + col.operator("node.backimage_fit", text="Fit") class NODE_PT_quality(bpy.types.Panel): @@ -414,6 +480,7 @@ class NODE_PT_quality(bpy.types.Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True snode = context.space_data tree = snode.node_tree @@ -457,19 +524,7 @@ class NODE_UL_interface_sockets(bpy.types.UIList): class NODE_PT_grease_pencil(GreasePencilDataPanel, Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - - @classmethod - def poll(cls, context): - snode = context.space_data - return snode is not None and snode.node_tree is not None - - -# Grease Pencil palette colors -class NODE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'UI' + bl_options = {'DEFAULT_CLOSED'} # NOTE: this is just a wrapper around the generic GP Panel @@ -498,31 +553,6 @@ class NODE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): bl_region_type = 'TOOLS' -# Grease Pencil stroke editing tools -class NODE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - - -# Grease Pencil stroke sculpting tools -class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - -# Grease Pencil drawing brushes - - -class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - -# Grease Pencil drawing curves - - -class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): - bl_space_type = 'NODE_EDITOR' - bl_region_type = 'TOOLS' - # ----------------------------- @@ -537,8 +567,9 @@ classes = ( NODE_MT_view, NODE_MT_select, NODE_MT_node, - NODE_MT_node_color_presets, + NODE_PT_node_color_presets, NODE_MT_node_color_specials, + NODE_MT_specials, NODE_PT_active_node_generic, NODE_PT_active_node_color, NODE_PT_active_node_properties, @@ -546,13 +577,8 @@ classes = ( NODE_PT_quality, NODE_UL_interface_sockets, NODE_PT_grease_pencil, - NODE_PT_grease_pencil_palettecolor, NODE_PT_grease_pencil_tools, NODE_PT_tools_grease_pencil_draw, - NODE_PT_tools_grease_pencil_edit, - NODE_PT_tools_grease_pencil_sculpt, - NODE_PT_tools_grease_pencil_brush, - NODE_PT_tools_grease_pencil_brushcurves, ) diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 4951ef83ad0..20ef5ae0c53 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -18,7 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu +from bpy.types import Header, Menu, Panel class OUTLINER_HT_header(Header): @@ -28,21 +28,47 @@ class OUTLINER_HT_header(Header): layout = self.layout space = context.space_data + display_mode = space.display_mode scene = context.scene ks = context.scene.keying_sets.active row = layout.row(align=True) row.template_header() - OUTLINER_MT_editor_menus.draw_collapsible(context, layout) + layout.prop(space, "display_mode", icon_only=True) - layout.prop(space, "display_mode", text="") + if display_mode == 'DATA_API': + OUTLINER_MT_editor_menus.draw_collapsible(context, layout) - layout.prop(space, "filter_text", icon='VIEWZOOM', text="") + layout.separator_spacer() - layout.separator() + row = layout.row(align=True) + row.prop(space, "filter_text", icon='VIEWZOOM', text="") + + layout.separator_spacer() + + row = layout.row(align=True) + if display_mode in {'VIEW_LAYER'}: + row.popover( + panel="OUTLINER_PT_filter", + text="", + icon='FILTER', + ) + elif display_mode in {'LIBRARIES', 'ORPHAN_DATA'}: + row.prop(space, "use_filter_id_type", text="", icon='FILTER') + sub = row.row(align=True) + sub.active = space.use_filter_id_type + sub.prop(space, "filter_id_type", text="", icon_only=True) + + if display_mode == 'VIEW_LAYER': + layout.operator("outliner.collection_new", text="", icon='GROUP').nested = True + + elif display_mode == 'ORPHAN_DATA': + layout.operator("outliner.orphans_purge", text="Purge") + + elif space.display_mode == 'DATA_API': + layout.separator() - if space.display_mode == 'DATABLOCKS': row = layout.row(align=True) row.operator("outliner.keyingset_add_selected", icon='ZOOMIN', text="") row.operator("outliner.keyingset_remove_selected", icon='ZOOMOUT', text="") @@ -57,8 +83,6 @@ class OUTLINER_HT_header(Header): else: row = layout.row() row.label(text="No Keying Set Active") - elif space.display_mode == 'ORPHAN_DATA': - layout.operator("outliner.orphans_purge") class OUTLINER_MT_editor_menus(Menu): @@ -72,71 +96,220 @@ class OUTLINER_MT_editor_menus(Menu): def draw_menus(layout, context): space = context.space_data - layout.menu("OUTLINER_MT_view") - layout.menu("OUTLINER_MT_search") - - if space.display_mode == 'DATABLOCKS': + if space.display_mode == 'DATA_API': layout.menu("OUTLINER_MT_edit_datablocks") -class OUTLINER_MT_view(Menu): - bl_label = "View" +class OUTLINER_MT_context(Menu): + bl_label = "Outliner" + + def draw(self, context): + layout = self.layout + + layout.operator("outliner.show_one_level", text="Show One Level") + layout.operator("outliner.show_one_level", text="Hide One Level").open = False + layout.operator("outliner.show_hierarchy") + + layout.separator() + + layout.operator("outliner.show_active") + + layout.separator() + + layout.menu("INFO_MT_area") + + +class OUTLINER_MT_edit_datablocks(Menu): + bl_label = "Edit" + + def draw(self, context): + layout = self.layout + + layout.operator("outliner.keyingset_add_selected") + layout.operator("outliner.keyingset_remove_selected") + + layout.separator() + + layout.operator("outliner.drivers_add_selected") + layout.operator("outliner.drivers_delete_selected") + + +class OUTLINER_MT_collection_view_layer(Menu): + bl_label = "View Layer" def draw(self, context): layout = self.layout space = context.space_data - if space.display_mode not in {'DATABLOCKS', 'USER_PREFERENCES'}: - layout.prop(space, "use_sort_alpha") - layout.prop(space, "show_restrict_columns") + layout.operator("outliner.collection_exclude_set") + layout.operator("outliner.collection_exclude_clear") + + if context.engine == 'CYCLES': + layout.operator("outliner.collection_indirect_only_set") + layout.operator("outliner.collection_indirect_only_clear") + + layout.operator("outliner.collection_holdout_set") + layout.operator("outliner.collection_holdout_clear") + + +class OUTLINER_MT_collection(Menu): + bl_label = "Collection" + + def draw(self, context): + layout = self.layout + + space = context.space_data + + layout.operator("outliner.collection_new", text="New").nested = True + layout.operator("outliner.collection_duplicate", text="Duplicate") + layout.operator("outliner.collection_delete", text="Delete").hierarchy = False + layout.operator("outliner.collection_delete", text="Delete Hierarchy").hierarchy = True + + layout.separator() + + layout.operator("outliner.collection_objects_select", text="Select Objects") + layout.operator("outliner.collection_objects_deselect", text="Deselect Objects") + + layout.separator() + + layout.operator("outliner.collection_instance", text="Instance to Scene") + if space.display_mode != 'VIEW_LAYER': + layout.operator("outliner.collection_link", text="Link to Scene") + layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK' + + if space.display_mode == 'VIEW_LAYER': layout.separator() - layout.operator("outliner.show_active") + layout.menu("OUTLINER_MT_collection_view_layer") + + layout.separator() + layout.operator_menu_enum("outliner.id_operation", "type", text="ID Data") + + layout.separator() + + OUTLINER_MT_context.draw(self, context) - layout.operator("outliner.show_one_level", text="Show One Level") - layout.operator("outliner.show_one_level", text="Hide One Level").open = False - layout.operator("outliner.show_hierarchy") + +class OUTLINER_MT_collection_new(Menu): + bl_label = "Collection" + + def draw(self, context): + layout = self.layout + + layout.operator("outliner.collection_new", text="New").nested = False layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + OUTLINER_MT_context.draw(self, context) -class OUTLINER_MT_search(Menu): - bl_label = "Search" +class OUTLINER_MT_object(Menu): + bl_label = "Object" def draw(self, context): layout = self.layout space = context.space_data + obj = context.active_object + object_mode = 'OBJECT' if obj is None else obj.mode - layout.prop(space, "use_filter_case_sensitive") - layout.prop(space, "use_filter_complete") + layout.operator("outliner.object_operation", text="Delete").type = 'DELETE' + if space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection: + layout.operator("outliner.object_operation", text="Delete Hierarchy").type = 'DELETE_HIERARCHY' + layout.separator() -class OUTLINER_MT_edit_datablocks(Menu): - bl_label = "Edit" + layout.operator("outliner.object_operation", text="Select").type = 'SELECT' + layout.operator("outliner.object_operation", text="Select Hierarchy").type = 'SELECT_HIERARCHY' + layout.operator("outliner.object_operation", text="Deselect").type = 'DESELECT' + + layout.separator() + + if object_mode in {'EDIT', 'POSE'}: + name = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode].name + layout.operator("outliner.object_operation", text=f"{name:s} Set").type = 'OBJECT_MODE_ENTER' + layout.operator("outliner.object_operation", text=f"{name:s} Clear").type = 'OBJECT_MODE_EXIT' + del name + + layout.separator() + + if not (space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection): + layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK' + layout.separator() + + layout.operator_menu_enum("outliner.id_operation", "type", text="ID Data") + + layout.separator() + + OUTLINER_MT_context.draw(self, context) + + +class OUTLINER_PT_filter(Panel): + bl_space_type = 'OUTLINER' + bl_region_type = 'HEADER' + bl_label = "Filter" def draw(self, context): layout = self.layout - layout.operator("outliner.keyingset_add_selected") - layout.operator("outliner.keyingset_remove_selected") + space = context.space_data + display_mode = space.display_mode + + layout.prop(space, "use_filter_complete", text="Exact Match Search") + layout.prop(space, "use_filter_case_sensitive", text="Case Sensitive Search") layout.separator() - layout.operator("outliner.drivers_add_selected") - layout.operator("outliner.drivers_delete_selected") + if space.display_mode != 'DATA_API': + layout.prop(space, "use_sort_alpha") + layout.prop(space, "show_restrict_columns") + layout.separator() + + col = layout.column(align=True) + + col.prop(space, "use_filter_collection", text="Collections", icon='GROUP') + col.prop(space, "use_filter_object", text="Objects", icon='OBJECT_DATAMODE') + + sub = col.column(align=True) + sub.active = space.use_filter_object + + if bpy.data.meshes: + sub.prop(space, "use_filter_object_mesh", text="Meshes", icon='MESH_DATA') + if bpy.data.armatures: + sub.prop(space, "use_filter_object_armature", text="Armatures", icon='ARMATURE_DATA') + if bpy.data.lights: + sub.prop(space, "use_filter_object_light", text="Lights", icon='LIGHT_DATA') + if bpy.data.cameras: + sub.prop(space, "use_filter_object_camera", text="Cameras", icon='CAMERA_DATA') + + sub.prop(space, "use_filter_object_empty", text="Empties", icon='EMPTY_DATA') + + if ( + bpy.data.curves or + bpy.data.metaballs or + bpy.data.lightprobes or + bpy.data.lattices or + bpy.data.fonts or + bpy.data.speakers + ): + sub.prop(space, "use_filter_object_others", text="Others") + + subsub = sub.column(align=False) + subsub.prop(space, "filter_state", text="") + subsub.prop(space, "use_filter_object_content", text="Object Contents") + subsub.prop(space, "use_filter_children", text="Object Children") classes = ( OUTLINER_HT_header, OUTLINER_MT_editor_menus, - OUTLINER_MT_view, - OUTLINER_MT_search, OUTLINER_MT_edit_datablocks, + OUTLINER_MT_collection, + OUTLINER_MT_collection_new, + OUTLINER_MT_collection_view_layer, + OUTLINER_MT_object, + OUTLINER_MT_context, + OUTLINER_PT_filter, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py index 20cb5719e20..2d1725b2087 100644 --- a/release/scripts/startup/bl_ui/space_properties.py +++ b/release/scripts/startup/bl_ui/space_properties.py @@ -31,6 +31,7 @@ class PROPERTIES_HT_header(Header): row = layout.row() row.template_header() + row.prop(view, "context", expand=True, icon_only=True) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index c3ca26efcb7..84ae59772b6 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -22,7 +22,6 @@ from bpy.types import Header, Menu, Panel from rna_prop_ui import PropertyPanel from .properties_grease_pencil_common import ( GreasePencilDataPanel, - GreasePencilPaletteColorPanel, GreasePencilToolsPanel, ) from bpy.app.translations import pgettext_iface as iface_ @@ -79,30 +78,29 @@ class SEQUENCER_HT_header(Header): row = layout.row(align=True) row.template_header() + layout.prop(st, "view_type", text="") + SEQUENCER_MT_editor_menus.draw_collapsible(context, layout) - row = layout.row(align=True) - row.prop(scene, "use_preview_range", text="", toggle=True) - row.prop(scene, "lock_frame_selection_to_range", text="", toggle=True) + if st.view_type == 'SEQUENCER': + layout.prop(st, "show_backdrop", text="Backdrop") - layout.prop(st, "view_type", expand=True, text="") + layout.separator_spacer() - if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}: - layout.prop(st, "display_mode", expand=True, text="") + layout.template_running_jobs() if st.view_type == 'SEQUENCER': - row = layout.row(align=True) - row.operator("sequencer.copy", text="", icon='COPYDOWN') - row.operator("sequencer.paste", text="", icon='PASTEDOWN') + layout.separator() + layout.operator("sequencer.refresh_all") + if st.view_type == 'SEQUENCER_PREVIEW': layout.separator() layout.operator("sequencer.refresh_all") - layout.prop(st, "show_backdrop") - else: - if st.view_type == 'SEQUENCER_PREVIEW': - layout.separator() - layout.operator("sequencer.refresh_all") + if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}: + layout.prop(st, "display_mode", expand=True, text="") + + if st.view_type != 'SEQUENCER': layout.prop(st, "preview_channels", expand=True, text="") layout.prop(st, "display_channel", text="Channel") @@ -134,7 +132,11 @@ class SEQUENCER_HT_header(Header): props.animation = True props.sequencer = True - layout.template_running_jobs() + if st.view_type == 'SEQUENCER': + + row = layout.row(align=True) + row.operator("sequencer.copy", text="", icon='COPYDOWN') + row.operator("sequencer.paste", text="", icon='PASTEDOWN') class SEQUENCER_MT_editor_menus(Menu): @@ -237,9 +239,7 @@ class SEQUENCER_MT_view(Menu): layout.prop(st, "use_marker_sync") layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class SEQUENCER_MT_select(Menu): @@ -248,6 +248,12 @@ class SEQUENCER_MT_select(Menu): def draw(self, context): layout = self.layout + layout.operator("sequencer.select_all", text="All").action = 'SELECT' + layout.operator("sequencer.select_all", text="None").action = 'DESELECT' + layout.operator("sequencer.select_all", text="Invert").action = 'INVERT' + + layout.separator() + layout.operator("sequencer.select_active_side", text="Strips to the Left").side = 'LEFT' layout.operator("sequencer.select_active_side", text="Strips to the Right").side = 'RIGHT' props = layout.operator("sequencer.select", text="All Strips to the Left") @@ -266,8 +272,6 @@ class SEQUENCER_MT_select(Menu): layout.operator("sequencer.select_linked") layout.operator("sequencer.select_less") layout.operator("sequencer.select_more") - layout.operator("sequencer.select_all").action = 'TOGGLE' - layout.operator("sequencer.select_all", text="Inverse").action = 'INVERT' class SEQUENCER_MT_marker(Menu): @@ -441,10 +445,6 @@ class SEQUENCER_MT_strip(Menu): layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("ed.undo") - layout.operator("ed.redo") - layout.operator("ed.undo_history") - layout.separator() layout.menu("SEQUENCER_MT_strip_transform") layout.operator("sequencer.snap") @@ -1280,14 +1280,6 @@ class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Ou # But, it should only show up when there are images in the preview region -class SEQUENCER_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, SequencerButtonsPanel_Output, Panel): - bl_space_type = 'SEQUENCE_EDITOR' - bl_region_type = 'UI' - - # NOTE: this is just a wrapper around the generic GP Panel - # But, it should only show up when there are images in the preview region - - class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel): bl_space_type = 'SEQUENCE_EDITOR' bl_region_type = 'UI' @@ -1298,7 +1290,7 @@ class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsP class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel): - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'} _context_path = "scene.sequence_editor.active_strip" _property_type = (bpy.types.Sequence,) bl_category = "Strip" @@ -1332,7 +1324,6 @@ classes = ( SEQUENCER_PT_view_safe_areas, SEQUENCER_PT_modifiers, SEQUENCER_PT_grease_pencil, - SEQUENCER_PT_grease_pencil_palettecolor, SEQUENCER_PT_grease_pencil_tools, SEQUENCER_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py new file mode 100644 index 00000000000..dbcfbf165ce --- /dev/null +++ b/release/scripts/startup/bl_ui/space_statusbar.py @@ -0,0 +1,68 @@ +# ##### 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> +import bpy +from bpy.types import Header + + +class STATUSBAR_HT_header(Header): + bl_space_type = 'STATUSBAR' + + def draw(self, context): + layout = self.layout + + # input status + layout.template_input_status() + + layout.separator_spacer() + + # messages + layout.template_reports_banner() + + row = layout.row(align=True) + if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False: + row.label("Auto-run disabled", icon='ERROR') + if bpy.data.is_saved: + props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted") + props.use_scripts = True + + row.operator("script.autoexec_warn_clear", text="Ignore") + + # include last so text doesn't push buttons out of the header + row.label(bpy.app.autoexec_fail_message) + + layout.template_running_jobs() + + layout.separator_spacer() + + # stats + scene = context.scene + view_layer = context.view_layer + + layout.label(text=scene.statistics(view_layer), translate=False) + + +classes = ( + STATUSBAR_HT_header, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index fc93956b14b..8e370326d8c 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -41,9 +41,13 @@ class TEXT_HT_header(Header): sub.alert = True sub.operator("text.resolve_conflict", text="", icon='HELP') + layout.separator_spacer() + row = layout.row(align=True) row.template_ID(st, "text", new="text.new", unlink="text.unlink", open="text.open") + layout.separator_spacer() + row = layout.row(align=True) row.prop(st, "show_line_numbers", text="") row.prop(st, "show_word_wrap", text="") @@ -52,17 +56,6 @@ class TEXT_HT_header(Header): if text: is_osl = text.name.endswith((".osl", ".osl")) - if is_osl: - row = layout.row() - row.operator("node.shader_script_update") - else: - row = layout.row() - row.operator("text.run_script") - - row = layout.row() - row.active = text.name.endswith(".py") - row.prop(text, "use_module") - row = layout.row() if text.filepath: if text.is_dirty: @@ -81,6 +74,16 @@ class TEXT_HT_header(Header): if text.library else "Text: Internal" ) + if is_osl: + row = layout.row() + row.operator("node.shader_script_update") + else: + row = layout.row() + row.active = text.name.endswith(".py") + row.prop(text, "use_module") + + row = layout.row() + row.operator("text.run_script") class TEXT_MT_editor_menus(Menu): @@ -186,9 +189,7 @@ class TEXT_MT_view(Menu): layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class TEXT_MT_text(Menu): diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 9026a93aa99..99e5f6b08e5 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -18,43 +18,27 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu +from bpy.types import Header, Menu, Panel -class TIME_HT_header(Header): - bl_space_type = 'TIMELINE' +# Header buttons for timeline header (play, etc.) +class TIME_HT_editor_buttons(Header): + bl_idname = "TIME_HT_editor_buttons" + bl_space_type = 'DOPESHEET_EDITOR' + bl_label = "" def draw(self, context): - layout = self.layout + pass + @staticmethod + def draw_header(context, layout): scene = context.scene toolsettings = context.tool_settings screen = context.screen - userprefs = context.user_preferences - row = layout.row(align=True) - row.template_header() - - TIME_MT_editor_menus.draw_collapsible(context, layout) - - row = layout.row(align=True) - row.prop(scene, "use_preview_range", text="", toggle=True) - row.prop(scene, "lock_frame_selection_to_range", text="", toggle=True) - - row = layout.row(align=True) - if not scene.use_preview_range: - row.prop(scene, "frame_start", text="Start") - row.prop(scene, "frame_end", text="End") - else: - row.prop(scene, "frame_preview_start", text="Start") - row.prop(scene, "frame_preview_end", text="End") - - if scene.show_subframe: - layout.prop(scene, "frame_float", text="") - else: - layout.prop(scene, "frame_current", text="") + layout.separator_spacer() - layout.separator() + layout.prop(toolsettings, "use_keyframe_insert_auto", text="", toggle=True) row = layout.row(align=True) row.operator("screen.frame_jump", text="", icon='REW').end = False @@ -65,37 +49,37 @@ class TIME_HT_header(Header): # since JACK transport doesn't support reversed playback if scene.sync_mode == 'AUDIO_SYNC' and context.user_preferences.system.audio_device == 'JACK': sub = row.row(align=True) - sub.scale_x = 2.0 + sub.scale_x = 1.4 sub.operator("screen.animation_play", text="", icon='PLAY') else: row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True row.operator("screen.animation_play", text="", icon='PLAY') else: sub = row.row(align=True) - sub.scale_x = 2.0 + sub.scale_x = 1.4 sub.operator("screen.animation_play", text="", icon='PAUSE') row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True row.operator("screen.frame_jump", text="", icon='FF').end = True - layout.prop(scene, "sync_mode", text="") - - layout.separator() - - row = layout.row(align=True) - row.prop(toolsettings, "use_keyframe_insert_auto", text="", toggle=True) - if toolsettings.use_keyframe_insert_auto: - row.prop(toolsettings, "use_keyframe_insert_keyingset", text="", toggle=True) - - if screen.is_animation_playing and not userprefs.edit.use_keyframe_insert_available: - subsub = row.row(align=True) - subsub.prop(toolsettings, "use_record_with_nla", toggle=True) + layout.separator_spacer() - layout.prop(toolsettings, "keyframe_type", text="", icon_only=True) + row = layout.row() + row.scale_x = 0.95 + if scene.show_subframe: + row.prop(scene, "frame_float", text="") + else: + row.prop(scene, "frame_current", text="") row = layout.row(align=True) - row.prop_search(scene.keying_sets_all, "active", scene, "keying_sets_all", text="") - row.operator("anim.keyframe_insert", text="", icon='KEY_HLT') - row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT') + row.prop(scene, "use_preview_range", text="", toggle=True) + sub = row.row(align=True) + sub.scale_x = 0.8 + if not scene.use_preview_range: + sub.prop(scene, "frame_start", text="Start") + sub.prop(scene, "frame_end", text="End") + else: + sub.prop(scene, "frame_preview_start", text="Start") + sub.prop(scene, "frame_preview_end", text="End") class TIME_MT_editor_menus(Menu): @@ -107,10 +91,20 @@ class TIME_MT_editor_menus(Menu): @staticmethod def draw_menus(layout, context): - layout.menu("TIME_MT_view") - layout.menu("TIME_MT_marker") - layout.menu("TIME_MT_frame") - layout.menu("TIME_MT_playback") + row = layout.row() + sub = row.row(align=True) + sub.popover( + panel="TIME_PT_playback", + text="Playback", + ) + sub.popover( + panel="TIME_PT_keyframing_settings", + text="Keying", + ) + + sub = row.row(align=True) + sub.menu("TIME_MT_view") + sub.menu("TIME_MT_marker") class TIME_MT_marker(Menu): @@ -138,7 +132,6 @@ class TIME_MT_view(Menu): layout.prop(st, "show_frame_indicator") layout.prop(scene, "show_keys_from_selected_only") - layout.prop(scene, "show_subframe") layout.separator() @@ -146,18 +139,13 @@ class TIME_MT_view(Menu): layout.separator() - layout.operator("time.view_all") - layout.operator("time.view_frame") - - layout.separator() - - layout.operator("marker.camera_bind") + # NOTE: "action" now, since timeline is in the dopesheet editor, instead of as own editor + layout.operator("action.view_all") + layout.operator("action.view_frame") layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class TIME_MT_cache(Menu): @@ -182,25 +170,56 @@ class TIME_MT_cache(Menu): col.prop(st, "cache_rigidbody") -class TIME_MT_frame(Menu): - bl_label = "Frame" +def marker_menu_generic(layout): + from bpy import context - def draw(self, context): - layout = self.layout + # layout.operator_context = 'EXEC_REGION_WIN' - layout.operator("anim.previewrange_clear") - layout.operator("anim.previewrange_set") - layout.separator() - layout.operator("time.end_frame_set") - layout.operator("time.start_frame_set") + layout.column() + layout.operator("marker.add", "Add Marker") + layout.operator("marker.duplicate", text="Duplicate Marker") - layout.separator() + if len(bpy.data.scenes) > 10: + layout.operator_context = 'INVOKE_DEFAULT' + layout.operator("marker.make_links_scene", text="Duplicate Marker to Scene...", icon='OUTLINER_OB_EMPTY') + else: + layout.operator_menu_enum("marker.make_links_scene", "scene", text="Duplicate Marker to Scene") - layout.menu("TIME_MT_autokey") + layout.operator("marker.delete", text="Delete Marker") + layout.separator() -class TIME_MT_playback(Menu): + layout.operator("marker.rename", text="Rename Marker") + layout.operator("marker.move", text="Grab/Move Marker") + + layout.separator() + + layout.operator("marker.camera_bind") + + layout.separator() + + layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True + layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False + + layout.separator() + ts = context.tool_settings + layout.prop(ts, "lock_markers") + +################################### + + +class TimelinePanelButtons: + bl_space_type = 'DOPESHEET_EDITOR' + bl_region_type = 'UI' + + @staticmethod + def has_timeline(context): + return context.space_data.mode == 'TIMELINE' + + +class TIME_PT_playback(TimelinePanelButtons, Panel): bl_label = "Playback" + bl_region_type = 'HEADER' def draw(self, context): layout = self.layout @@ -208,7 +227,20 @@ class TIME_MT_playback(Menu): screen = context.screen scene = context.scene - layout.prop(screen, "use_play_top_left_3d_editor") + layout.prop(scene, "sync_mode", text="") + layout.prop(scene, "use_audio_scrub") + layout.prop(scene, "use_audio", text="Mute Audio") + + layout.prop(scene, "show_subframe", text="Subframes") + + layout.prop(scene, "lock_frame_selection_to_range", text="Limit Playhead to Frame Range") + layout.prop(screen, "use_follow", text="Follow Playhead") + + layout.separator() + + col = layout.column() + col.label("Play Animation In:") + layout.prop(screen, "use_play_top_left_3d_editor", text="Active Editor Only") layout.prop(screen, "use_play_3d_editors") layout.prop(screen, "use_play_animation_editors") layout.prop(screen, "use_play_properties_editors") @@ -218,67 +250,59 @@ class TIME_MT_playback(Menu): layout.prop(screen, "use_play_clip_editors") layout.separator() - layout.prop(screen, "use_follow") - layout.separator() - layout.prop(scene, "use_frame_drop", text="Frame Dropping") - layout.prop(scene, "use_audio_sync", text="AV-sync", icon='SPEAKER') - layout.prop(scene, "use_audio") - layout.prop(scene, "use_audio_scrub") + row = layout.row(align=True) + row.operator("anim.start_frame_set") + row.operator("anim.end_frame_set") -class TIME_MT_autokey(Menu): - bl_label = "Auto-Keyframing Mode" +class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel): + bl_label = "Keyframing Settings" + bl_options = {'HIDE_HEADER'} + bl_region_type = 'HEADER' + + @classmethod + def poll(cls, context): + # only for timeline editor + return cls.has_timeline(context) def draw(self, context): layout = self.layout - toolsettings = context.tool_settings - - layout.prop_enum(toolsettings, "auto_keying_mode", 'ADD_REPLACE_KEYS') - layout.prop_enum(toolsettings, "auto_keying_mode", 'REPLACE_KEYS') - - -def marker_menu_generic(layout): - from bpy import context - # layout.operator_context = 'EXEC_REGION_WIN' - - layout.column() - layout.operator("marker.add", "Add Marker") - layout.operator("marker.duplicate", text="Duplicate Marker") - - if len(bpy.data.scenes) > 10: - layout.operator_context = 'INVOKE_DEFAULT' - layout.operator("marker.make_links_scene", text="Duplicate Marker to Scene...", icon='OUTLINER_OB_EMPTY') - else: - layout.operator_menu_enum("marker.make_links_scene", "scene", text="Duplicate Marker to Scene") - - layout.operator("marker.delete", text="Delete Marker") - - layout.separator() + scene = context.scene + toolsettings = context.tool_settings + userprefs = context.user_preferences - layout.operator("marker.rename", text="Rename Marker") - layout.operator("marker.move", text="Grab/Move Marker") + col = layout.column(align=True) + col.label("Active Keying Set:") + row = col.row(align=True) + row.prop_search(scene.keying_sets_all, "active", scene, "keying_sets_all", text="") + row.operator("anim.keyframe_insert", text="", icon='KEY_HLT') + row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT') - layout.separator() + col = layout.column(align=True) + col.label("New Keyframe Type:") + col.prop(toolsettings, "keyframe_type", text="") - layout.operator("screen.marker_jump", text="Jump to Next Marker").next = True - layout.operator("screen.marker_jump", text="Jump to Previous Marker").next = False + col = layout.column(align=True) + col.label("Auto Keyframing:") + row = col.row() + row.prop(toolsettings, "auto_keying_mode", text="") + row.prop(toolsettings, "use_keyframe_insert_keyingset", text="") + if not userprefs.edit.use_keyframe_insert_available: + col.prop(toolsettings, "use_record_with_nla", text="Layered Recording") - layout.separator() - ts = context.tool_settings - layout.prop(ts, "lock_markers") +################################### classes = ( - TIME_HT_header, + TIME_HT_editor_buttons, TIME_MT_editor_menus, TIME_MT_marker, TIME_MT_view, TIME_MT_cache, - TIME_MT_frame, - TIME_MT_playback, - TIME_MT_autokey, + TIME_PT_playback, + TIME_PT_keyframing_settings, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py new file mode 100644 index 00000000000..91ded3e4456 --- /dev/null +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -0,0 +1,727 @@ +# ##### 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> +import bpy +from bpy.types import ( + Menu, +) + +__all__ = ( + "ToolSelectPanelHelper", + "ToolDef", +) + +# Support reloading icons. +if "_icon_cache" in locals(): + release = bpy.app.icons.release + for icon_value in _icon_cache.values(): + if icon_value != 0: + release(icon_value) + del release + + +# (filename -> icon_value) map +_icon_cache = {} + + +def _keymap_fn_from_seq(keymap_data): + + # standalone + def _props_assign_recursive(rna_props, py_props): + for prop_id, value in py_props.items(): + if isinstance(value, dict): + _props_assign_recursive(getattr(rna_props, prop_id), value) + else: + setattr(rna_props, prop_id, value) + + def keymap_fn(km): + for op_idname, op_props_dict, kmi_kwargs in keymap_fn.keymap_data: + kmi = km.keymap_items.new(op_idname, **kmi_kwargs) + kmi_props = kmi.properties + if op_props_dict: + _props_assign_recursive(kmi.properties, op_props_dict) + keymap_fn.keymap_data = keymap_data + return keymap_fn + + +def _item_is_fn(item): + return (not (type(item) is ToolDef) and callable(item)) + + +from collections import namedtuple +ToolDef = namedtuple( + "ToolDef", + ( + # The name to display in the interface. + "text", + # The name of the icon to use (found in ``release/datafiles/icons``) or None for no icon. + "icon", + # An optional cursor to use when this tool is active. + "cursor", + # An optional gizmo group to activate when the tool is set or None for no gizmo. + "widget", + # Optional keymap for tool, either: + # - A function that populates a keymaps passed in as an argument. + # - A tuple filled with triple's of: + # ``(operator_id, operator_properties, keymap_item_args)``. + # + # Warning: currently 'from_dict' this is a list of one item, + # so internally we can swap the keymap function for the keymap it's self. + # This isn't very nice and may change, tool definitions shouldn't care about this. + "keymap", + # Optional data-block assosiated with this tool. + # (Typically brush name, usage depends on mode, we could use for non-brush ID's in other modes). + "data_block", + # Optional primary operator (for introspection only). + "operator", + # Optional draw settings (operator options, toolsettings). + "draw_settings", + ) +) +del namedtuple + + +def from_dict(kw_args): + """ + Use so each tool can avoid defining all members of the named tuple. + Also convert the keymap from a tuple into a function + (since keymap is a callback). + """ + kw = { + "icon": None, + "cursor": None, + "widget": None, + "keymap": None, + "data_block": None, + "operator": None, + "draw_settings": None, + } + kw.update(kw_args) + + keymap = kw["keymap"] + if kw["keymap"] is None: + pass + elif type(keymap) is tuple: + keymap = [_keymap_fn_from_seq(keymap)] + else: + keymap = [keymap] + kw["keymap"] = keymap + return ToolDef(**kw) + + +def from_fn(fn): + """ + Use as decorator so we can define functions. + """ + return ToolDef.from_dict(fn()) + + +ToolDef.from_dict = from_dict +ToolDef.from_fn = from_fn +del from_dict +del from_fn + + +class ToolSelectPanelHelper: + """ + Generic Class, can be used for any toolbar. + + - keymap_prefix: + The text prefix for each key-map for this spaces tools. + - tools_all(): + Returns (context_mode, tools) tuple pair for all tools defined. + - tools_from_context(context, mode=None): + Returns tools available in this context. + + Each tool is a 'ToolDef' or None for a separator in the toolbar, use ``None``. + """ + + @staticmethod + def _tool_class_from_space_type(space_type): + return next( + (cls for cls in ToolSelectPanelHelper.__subclasses__() + if cls.bl_space_type == space_type), + None + ) + + @staticmethod + def _icon_value_from_icon_handle(icon_name): + import os + if icon_name is not None: + assert(type(icon_name) is str) + icon_value = _icon_cache.get(icon_name) + if icon_value is None: + dirname = bpy.utils.resource_path('LOCAL') + if not os.path.exists(dirname): + # TODO(campbell): use a better way of finding datafiles. + dirname = bpy.utils.resource_path('SYSTEM') + filename = os.path.join(dirname, "datafiles", "icons", icon_name + ".dat") + try: + icon_value = bpy.app.icons.new_triangles_from_file(filename) + except Exception as ex: + if not os.path.exists(filename): + print("Missing icons:", filename, ex) + else: + print("Corrupt icon:", filename, ex) + # Use none as a fallback (avoids layout issues). + if icon_name != "none": + icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle("none") + else: + icon_value = 0 + _icon_cache[icon_name] = icon_value + return icon_value + else: + return 0 + + @staticmethod + def _tools_flatten(tools): + """ + Flattens, skips None and calls generators. + """ + for item in tools: + if item is None: + yield None + elif type(item) is tuple: + for sub_item in item: + if sub_item is None: + yield None + elif _item_is_fn(sub_item): + yield from sub_item(context) + else: + yield sub_item + else: + if _item_is_fn(item): + yield from item(context) + else: + yield item + + @staticmethod + def _tools_flatten_with_tool_index(tools): + for item in tools: + if item is None: + yield None, -1 + elif type(item) is tuple: + i = 0 + for sub_item in item: + if sub_item is None: + yield None + elif _item_is_fn(sub_item): + for item_dyn in sub_item(context): + yield item_dyn, i + i += 1 + else: + yield sub_item, i + i += 1 + else: + if _item_is_fn(item): + for item_dyn in item(context): + yield item_dyn, -1 + else: + yield item, -1 + + @staticmethod + def _tool_get_active(context, space_type, mode, with_icon=False): + """ + Return the active Python tool definition and icon name. + """ + workspace = context.workspace + cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) + if cls is not None: + tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode) + tool_active_text = getattr(tool_active, "name", None) + for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)): + if item is not None: + if item.text == tool_active_text: + if with_icon: + icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) + else: + icon_value = 0 + return (item, tool_active, icon_value) + return None, None, 0 + + @staticmethod + def _tool_get_by_name(context, space_type, text): + """ + Return the active Python tool definition and index (if in sub-group, else -1). + """ + cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) + if cls is not None: + for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)): + if item is not None: + if item.text == text: + return (cls, item, index) + return None, None, -1 + + @staticmethod + def _tool_active_from_context(context, space_type, mode=None, create=False): + if space_type == 'VIEW_3D': + if mode is None: + mode = context.mode + tool = context.workspace.tools.from_space_view3d_mode(mode, create) + if tool is not None: + tool.refresh_from_context() + return tool + elif space_type == 'IMAGE_EDITOR': + space_data = context.space_data + if mode is None: + mode = space_data.mode + tool = context.workspace.tools.from_space_image_mode(mode, create) + if tool is not None: + tool.refresh_from_context() + return tool + return None + + @staticmethod + def _tool_text_from_button(context): + return context.button_operator.name + + @classmethod + def _km_action_simple(cls, kc, context_mode, text, keymap_fn): + if context_mode is None: + context_mode = "All" + km_idname = f"{cls.keymap_prefix:s} {context_mode:s}, {text:s}" + km = kc.keymaps.get(km_idname) + if km is None: + km = kc.keymaps.new(km_idname, space_type=cls.bl_space_type, region_type='WINDOW') + keymap_fn[0](km) + keymap_fn[0] = km + + @classmethod + def register(cls): + wm = bpy.context.window_manager + + # XXX, should we be manipulating the user-keyconfig on load? + # Perhaps this should only add when keymap items don't already exist. + # + # This needs some careful consideration. + kc = wm.keyconfigs.user + + # Track which tool-group was last used for non-active groups. + # Blender stores the active tool-group index. + # + # {tool_name_first: index_in_group, ...} + cls._tool_group_active = {} + + # ignore in background mode + if kc is None: + return + + for context_mode, tools in cls.tools_all(): + for item_parent in tools: + if item_parent is None: + continue + for item in item_parent if (type(item_parent) is tuple) else (item_parent,): + # skip None or generator function + if item is None or _item_is_fn(item): + continue + keymap_data = item.keymap + if keymap_data is not None and callable(keymap_data[0]): + text = item.text + icon_name = item.icon + cls._km_action_simple(kc, context_mode, text, keymap_data) + + # ------------------------------------------------------------------------- + # Layout Generators + # + # Meaning of recieved values: + # - Bool: True for a separator, otherwise False for regular tools. + # - None: Signal to finish (complete any final operations, e.g. add padding). + + @staticmethod + def _layout_generator_single_column(layout, scale_y): + col = layout.column(align=True) + col.scale_y = scale_y + is_sep = False + while True: + if is_sep is True: + col = layout.column(align=True) + col.scale_y = scale_y + elif is_sep is None: + yield None + return + is_sep = yield col + + @staticmethod + def _layout_generator_multi_columns(layout, column_count, scale_y): + scale_x = scale_y * 1.1 + column_last = column_count - 1 + + col = layout.column(align=True) + + row = col.row(align=True) + + row.scale_x = scale_x + row.scale_y = scale_y + + is_sep = False + column_index = 0 + while True: + if is_sep is True: + if column_index != column_last: + row.label("") + col = layout.column(align=True) + row = col.row(align=True) + row.scale_x = scale_x + row.scale_y = scale_y + column_index = 0 + + is_sep = yield row + if is_sep is None: + if column_index == column_last: + row.label("") + yield None + return + + if column_index == column_count: + column_index = 0 + row = col.row(align=True) + row.scale_x = scale_x + row.scale_y = scale_y + column_index += 1 + + @staticmethod + def _layout_generator_detect_from_region(layout, region, scale_y): + """ + Choose an appropriate layout for the toolbar. + """ + # Currently this just checks the width, + # we could have different layouts as preferences too. + system = bpy.context.user_preferences.system + view2d = region.view2d + view2d_scale = ( + view2d.region_to_view(1.0, 0.0)[0] - + view2d.region_to_view(0.0, 0.0)[0] + ) + width_scale = region.width * view2d_scale / system.ui_scale + + if width_scale > 120.0: + show_text = True + column_count = 1 + else: + show_text = False + # 2 column layout, disabled + if width_scale > 80.0: + column_count = 2 + use_columns = True + else: + column_count = 1 + + if column_count == 1: + ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y=scale_y) + else: + ui_gen = ToolSelectPanelHelper._layout_generator_multi_columns(layout, column_count=column_count, scale_y=scale_y) + + return ui_gen, show_text + + @classmethod + def draw_cls(cls, layout, context, detect_layout=True, scale_y=1.75): + # Use a classmethod so it can be called outside of a panel context. + + # XXX, this UI isn't very nice. + # We might need to create new button types for this. + # Since we probably want: + # - tool-tips that include multiple key shortcuts. + # - ability to click and hold to expose sub-tools. + + space_type = context.space_data.type + tool_active_text = getattr( + ToolSelectPanelHelper._tool_active_from_context(context, space_type), + "name", None, + ) + + if detect_layout: + ui_gen, show_text = cls._layout_generator_detect_from_region(layout, context.region, scale_y) + else: + ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y) + show_text = True + + # Start iteration + ui_gen.send(None) + + for item in cls.tools_from_context(context): + if item is None: + ui_gen.send(True) + continue + + if type(item) is tuple: + is_active = False + i = 0 + for i, sub_item in enumerate(item): + if sub_item is None: + continue + is_active = (sub_item.text == tool_active_text) + if is_active: + index = i + break + del i, sub_item + + if is_active: + # not ideal, write this every time :S + cls._tool_group_active[item[0].text] = index + else: + index = cls._tool_group_active.get(item[0].text, 0) + + item = item[index] + use_menu = True + else: + index = -1 + use_menu = False + + is_active = (item.text == tool_active_text) + icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) + + sub = ui_gen.send(False) + + if use_menu: + sub.operator_menu_hold( + "wm.tool_set_by_name", + text=item.text if show_text else "", + depress=is_active, + menu="WM_MT_toolsystem_submenu", + icon_value=icon_value, + ).name = item.text + else: + sub.operator( + "wm.tool_set_by_name", + text=item.text if show_text else "", + depress=is_active, + icon_value=icon_value, + ).name = item.text + # Signal to finish any remaining layout edits. + ui_gen.send(None) + + def draw(self, context): + self.draw_cls(self.layout, context) + + @staticmethod + def draw_active_tool_header(context, layout): + # BAD DESIGN WARNING: last used tool + workspace = context.workspace + space_type = workspace.tools_space_type + mode = workspace.tools_mode + item, tool, icon_value = ToolSelectPanelHelper._tool_get_active(context, space_type, mode, with_icon=True) + if item is None: + return + # Note: we could show 'item.text' here but it makes the layout jitter when switcuing tools. + layout.label(" ", icon_value=icon_value) + draw_settings = item.draw_settings + if draw_settings is not None: + draw_settings(context, layout, tool) + + +# The purpose of this menu is to be a generic popup to select between tools +# in cases when a single tool allows to select alternative tools. +class WM_MT_toolsystem_submenu(Menu): + bl_label = "" + + @staticmethod + def _tool_group_from_button(context): + # Lookup the tool definitions based on the space-type. + cls = ToolSelectPanelHelper._tool_class_from_space_type(context.space_data.type) + if cls is not None: + button_text = ToolSelectPanelHelper._tool_text_from_button(context) + for item_group in cls.tools_from_context(context): + if type(item_group) is tuple: + for sub_item in item_group: + if sub_item.text == button_text: + return cls, item_group + return None, None + + def draw(self, context): + layout = self.layout + layout.scale_y = 2.0 + + cls, item_group = self._tool_group_from_button(context) + if item_group is None: + # Should never happen, just in case + layout.label("Unable to find toolbar group") + return + + for item in item_group: + if item is None: + layout.separator() + continue + icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) + layout.operator( + "wm.tool_set_by_name", + text=item.text, + icon_value=icon_value, + ).name = item.text + + +def _activate_by_item(context, space_type, item, index): + tool = ToolSelectPanelHelper._tool_active_from_context(context, space_type, create=True) + tool.setup( + name=item.text, + keymap=item.keymap[0].name if item.keymap is not None else "", + cursor=item.cursor or 'DEFAULT', + gizmo_group=item.widget or "", + data_block=item.data_block or "", + operator=item.operator or "", + index=index, + ) + + +def activate_by_name(context, space_type, text): + cls, item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text) + if item is None: + return False + _activate_by_item(context, space_type, item, index) + return True + + +def activate_by_name_or_cycle(context, space_type, text, offset=1): + + # Only cycle when the active tool is activated again. + cls, item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text) + if item is None: + return False + + tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type) + text_active = getattr(tool_active, "name", None) + + text_current = "" + for item_group in cls.tools_from_context(context): + if type(item_group) is tuple: + index_current = cls._tool_group_active.get(item_group[0].text, 0) + ok = False + for i, sub_item in enumerate(item_group): + if sub_item.text == text: + text_current = item_group[index_current].text + break + if text_current: + break + + if text_current == "": + return activate_by_name(context, space_type, text) + if text_active != text_current: + return activate_by_name(context, space_type, text_current) + + index_found = (tool_active.index + offset) % len(item_group) + + cls._tool_group_active[item_group[0].text] = index_found + + item_found = item_group[index_found] + _activate_by_item(context, space_type, item_found, index_found) + return True + + +def keymap_from_context(context, space_type): + """ + Keymap for popup toolbar, currently generated each time. + """ + + def modifier_keywords_from_item(kmi): + return { + "any": kmi.any, + "shift": kmi.shift, + "ctrl": kmi.ctrl, + "alt": kmi.alt, + "oskey": kmi.oskey, + "key_modifier": kmi.key_modifier, + } + + use_search = False # allows double tap + use_simple_keymap = False + + km_name = "Toolbar Popup" + wm = context.window_manager + keyconf = wm.keyconfigs.active + keymap = keyconf.keymaps.get(km_name) + if keymap is None: + keymap = keyconf.keymaps.new(km_name, space_type='EMPTY', region_type='TEMPORARY') + for kmi in keymap.keymap_items: + keymap.keymap_items.remove(kmi) + + if use_search: + kmi_search = wm.keyconfigs.find_item_from_operator(idname="wm.toolbar")[1] + kmi_search_type = None if not kmi_search else kmi_search.type + + items = [] + cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) + for i, item in enumerate( + ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context)) + ): + if item is not None: + if use_simple_keymap: + # Simply assign a key from A-Z + items.append(((chr(ord('A') + i)), item.text)) + kmi = keymap.keymap_items.new("wm.tool_set_by_name", key, 'PRESS') + kmi.properties.name = item.text + continue + + # Only check the first item in the tools key-map (a little arbitrary). + if item.operator is not None: + kmi_found = wm.keyconfigs.find_item_from_operator( + idname=item.operator, + )[1] + elif item.keymap is not None: + kmi_first = item.keymap[0].keymap_items[0] + kmi_found = wm.keyconfigs.find_item_from_operator( + idname=kmi_first.idname, + # properties=kmi_first.properties, # prevents matches, don't use. + )[1] + del kmi_first + else: + kmi_found = None + + if kmi_found is not None: + kmi_found_type = kmi_found.type + # Only for single keys. + if len(kmi_found_type) == 1: + kmi = keymap.keymap_items.new( + idname="wm.tool_set_by_name", + type=kmi_found_type, + value='PRESS', + **modifier_keywords_from_item(kmi_found), + ) + kmi.properties.name = item.text + + if use_search: + # Disallow overlap + if kmi_search_type == kmi_found_type: + kmi_search_type = None + + if use_search: + # Support double-tap for search. + if kmi_search_type: + keymap.keymap_items.new("wm.search_menu", type=kmi_search_type, value='PRESS') + else: + # The shortcut will show, so we better support running it. + kmi_search = wm.keyconfigs.find_item_from_operator(idname="wm.search_menu")[1] + if kmi_search: + keymap.keymap_items.new( + "wm.search_menu", + type=kmi_search.type, + value='PRESS', + **modifier_keywords_from_item(kmi_search), + ) + + wm.keyconfigs.update() + return keymap + + +classes = ( + WM_MT_toolsystem_submenu, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py new file mode 100644 index 00000000000..e1ecba1550a --- /dev/null +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -0,0 +1,1645 @@ +# ##### 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> + +# For now group all tools together +# we may want to move these into per space-type files. +# +# For now keep this in a single file since it's an area that may change, +# so avoid making changes all over the place. + +import bpy +from bpy.types import Panel + +from .space_toolsystem_common import ( + ToolSelectPanelHelper, + ToolDef, +) + + +def generate_from_brushes_ex( + context, *, + icon_prefix, + brush_test_attr, + brush_category_attr, + brush_category_layout, +): + # Categories + brush_categories = {} + if context.mode != 'GPENCIL_PAINT': + for brush in context.blend_data.brushes: + if getattr(brush, brush_test_attr) and brush.gpencil_settings is None: + category = getattr(brush, brush_category_attr) + name = brush.name + brush_categories.setdefault(category, []).append( + ToolDef.from_dict( + dict( + text=name, + icon=icon_prefix + category.lower(), + data_block=name, + ) + ) + ) + else: + def draw_settings(context, layout, tool): + _defs_gpencil_paint.draw_settings_common(context, layout, tool) + + for brush_type in brush_category_layout: + for brush in context.blend_data.brushes: + if getattr(brush, brush_test_attr) and brush.gpencil_settings.gp_icon == brush_type[0]: + category = brush_type[0] + name = brush.name + text = name + + # XXX, disabled since changing the brush needs to sync back to the tool. + """ + # rename default brushes for tool bar + if name.startswith("Draw "): + text = name.replace("Draw ", "") + elif name.startswith("Eraser "): + text = name.replace("Eraser ", "") + elif name.startswith("Fill "): + text = name.replace(" Area", "") + else: + text = name + """ + # Define icon. + icon_name = { + 'PENCIL': 'draw_pencil', + 'PEN': 'draw_pen', + 'INK': 'draw_ink', + 'INKNOISE': 'draw_noise', + 'BLOCK': 'draw_block', + 'MARKER': 'draw_marker', + 'FILL': 'draw_fill', + 'SOFT': 'draw.eraser_soft', + 'HARD': 'draw.eraser_hard', + 'STROKE': 'draw.eraser_stroke', + }[category] + brush_categories.setdefault(category, []).append( + ToolDef.from_dict( + dict( + text=text, + icon=icon_prefix + icon_name, + data_block=name, + widget=None, + operator="gpencil.draw", + draw_settings=draw_settings, + ) + ) + ) + + def tools_from_brush_group(groups): + assert(type(groups) is tuple) + if len(groups) == 1: + tool_defs = tuple(brush_categories.pop(groups[0], ())) + else: + tool_defs = tuple(item for g in groups for item in brush_categories.pop(g, ())) + + if len(tool_defs) > 1: + return (tool_defs,) + else: + return tool_defs + + # Each item below is a single toolbar entry: + # Grouped for multiple or none if no brushes are found. + tool_defs = tuple( + tool_def + for category in brush_category_layout + for tool_def in tools_from_brush_group(category) + ) + # Ensure we use all types. + if brush_categories: + print(brush_categories) + assert(len(brush_categories) == 0) + return tool_defs + + +def generate_from_enum_ex( + context, *, + icon_prefix, + data, + attr, +): + tool_defs = [] + for enum in data.rna_type.properties[attr].enum_items_static: + name = enum.name + identifier = enum.identifier + tool_defs.append( + ToolDef.from_dict( + dict( + text=name, + icon=icon_prefix + identifier.lower(), + data_block=identifier, + ) + ) + ) + return tuple(tool_defs) + + +class _defs_view3d_generic: + @ToolDef.from_fn + def cursor(): + def draw_settings(context, layout, tool): + wm = context.window_manager + props = tool.operator_properties("view3d.cursor3d") + layout.prop(props, "use_depth") + layout.prop(props, "orientation") + + return dict( + text="Cursor", + icon="ops.generic.cursor", + keymap=( + ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ("transform.translate", + dict(release_confirm=True, cursor_transform=True), + dict(type='EVT_TWEAK_A', value='ANY'), + ), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def cursor_click(): + return dict( + text="None", + icon="ops.generic.cursor", + keymap=( + # This is a dummy keymap entry, until particle system is properly working with toolsystem. + ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='CLICK', ctrl=True, alt=True, shift=True)), + ), + ) + + @ToolDef.from_fn + def ruler(): + return dict( + text="Ruler", + icon="ops.view3d.ruler", + widget="VIEW3D_GGT_ruler", + keymap=( + ("view3d.ruler_add", dict(), dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + +class _defs_annotate: + @classmethod + def draw_settings_common(cls, context, layout, tool): + ts = context.tool_settings + + space_type = tool.space_type + if space_type == 'VIEW_3D': + layout.separator() + + row = layout.row(align=True) + row.prop(ts, "annotation_stroke_placement_view3d", text="Placement") + if ts.gpencil_stroke_placement_view3d == 'CURSOR': + row.prop(ts.gpencil_sculpt, "lockaxis") + elif ts.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}: + row.prop(ts, "use_gpencil_stroke_endpoints") + + @ToolDef.from_fn + def scribble(): + def draw_settings(context, layout, tool): + _defs_annotate.draw_settings_common(context, layout, tool) + + return dict( + text="Annotate", + icon="ops.gpencil.draw", + cursor='PAINT_BRUSH', + keymap=( + ("gpencil.annotate", + dict(mode='DRAW', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def line(): + def draw_settings(context, layout, tool): + _defs_annotate.draw_settings_common(context, layout, tool) + + return dict( + text="Draw Line", + icon="ops.gpencil.draw.line", + cursor='CROSSHAIR', + keymap=( + ("gpencil.annotate", + dict(mode='DRAW_STRAIGHT', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def poly(): + def draw_settings(context, layout, tool): + _defs_annotate.draw_settings_common(context, layout, tool) + + return dict( + text="Draw Polygon", + icon="ops.gpencil.draw.poly", + cursor='CROSSHAIR', + keymap=( + ("gpencil.annotate", + dict(mode='DRAW_POLY', wait_for_input=False), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def eraser(): + def draw_settings(context, layout, tool): + # TODO: Move this setting to toolsettings + user_prefs = context.user_preferences + layout.prop(user_prefs.edit, "grease_pencil_eraser_radius", text="Radius") + + return dict( + text="Eraser", + icon="ops.gpencil.draw.eraser", + cursor='CROSSHAIR', # XXX: Always show brush circle when enabled + keymap=( + ("gpencil.annotate", + dict(mode='ERASER', wait_for_input=False), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + +class _defs_transform: + + @ToolDef.from_fn + def translate(): + def draw_settings(context, layout, tool): + tool_settings = context.tool_settings + layout.prop(tool_settings, "use_gizmo_apron") + + return dict( + text="Grab", + # cursor='SCROLL_XY', + icon="ops.transform.translate", + widget="TRANSFORM_GGT_gizmo", + operator="transform.translate", + # TODO, implement as optional fallback gizmo + # keymap=( + # ("transform.translate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')), + # ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def rotate(): + def draw_settings(context, layout, tool): + tool_settings = context.tool_settings + layout.prop(tool_settings, "use_gizmo_apron") + + return dict( + text="Rotate", + # cursor='SCROLL_XY', + icon="ops.transform.rotate", + widget="TRANSFORM_GGT_gizmo", + operator="transform.rotate", + # TODO, implement as optional fallback gizmo + # keymap=( + # ("transform.rotate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')), + # ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def scale(): + def draw_settings(context, layout, tool): + tool_settings = context.tool_settings + layout.prop(tool_settings, "use_gizmo_apron") + + return dict( + text="Scale", + # cursor='SCROLL_XY', + icon="ops.transform.resize", + widget="TRANSFORM_GGT_gizmo", + operator="transform.resize", + # TODO, implement as optional fallback gizmo + # keymap=( + # ("transform.resize", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')), + # ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def scale_cage(): + return dict( + text="Scale Cage", + icon="ops.transform.resize.cage", + widget="VIEW3D_GGT_xform_cage", + operator="transform.resize", + ) + + @ToolDef.from_fn + def transform(): + def draw_settings(context, layout, tool): + tool_settings = context.tool_settings + layout.prop(tool_settings, "use_gizmo_apron") + layout.prop(tool_settings, "use_gizmo_mode") + + return dict( + text="Transform", + icon="ops.transform.transform", + widget="TRANSFORM_GGT_gizmo", + # No keymap default action, only for gizmo! + draw_settings=draw_settings, + ) + + +class _defs_view3d_select: + + @ToolDef.from_fn + def border(): + return dict( + text="Select Border", + icon="ops.generic.select_border", + widget=None, + keymap=( + ("view3d.select_border", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ("view3d.select_border", + dict(deselect=True), + dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def circle(): + return dict( + text="Select Circle", + icon="ops.generic.select_circle", + widget=None, + keymap=( + ("view3d.select_circle", + dict(deselect=False), + dict(type='ACTIONMOUSE', value='PRESS')), + ("view3d.select_circle", + dict(deselect=True), + dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def lasso(): + return dict( + text="Select Lasso", + icon="ops.generic.select_lasso", + widget=None, + keymap=( + ("view3d.select_lasso", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ("view3d.select_lasso", + dict(deselect=True), + dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) +# ----------------------------------------------------------------------------- +# Object Modes (named based on context.mode) + + +class _defs_edit_armature: + + @ToolDef.from_fn + def roll(): + return dict( + text="Roll", + icon="ops.armature.bone.roll", + widget=None, + keymap=( + ("transform.transform", + dict(release_confirm=True, mode='BONE_ROLL'), + dict(type='EVT_TWEAK_A', value='ANY'),), + ), + ) + + @ToolDef.from_fn + def bone_envelope(): + return dict( + text="Bone Envelope", + icon="ops.transform.bone_envelope", + widget=None, + keymap=( + ("transform.transform", + dict(release_confirm=True, mode='BONE_ENVELOPE'), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def bone_size(): + return dict( + text="Bone Size", + icon="ops.transform.bone_size", + widget=None, + keymap=( + ("transform.transform", + dict(release_confirm=True, mode='BONE_SIZE'), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def extrude(): + return dict( + text="Extrude", + icon="ops.armature.extrude_move", + widget=None, + keymap=( + ("armature.click_extrude", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def extrude_cursor(): + return dict( + text="Extrude to Cursor", + icon="ops.armature.extrude_cursor", + widget=None, + keymap=( + ("armature.click_extrude", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + +class _defs_edit_mesh: + + @ToolDef.from_fn + def cube_add(): + return dict( + text="Add Cube", + icon="ops.mesh.primitive_cube_add_manipulator", + widget=None, + keymap=( + ("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='CLICK')), + ("mesh.primitive_cube_add_gizmo", dict(), dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def rip_region(): + def draw_settings(context, layout, tool): + wm = context.window_manager + props = tool.operator_properties("mesh.rip_move") + props_macro = props.MESH_OT_rip + layout.prop(props_macro, "use_fill") + + return dict( + text="Rip Region", + icon="ops.mesh.rip", + widget=None, + keymap=( + ("mesh.rip_move", + dict(TRANSFORM_OT_translate=dict(release_confirm=True)), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def rip_edge(): + return dict( + text="Rip Edge", + icon="ops.mesh.rip_edge", + widget=None, + keymap=( + ("mesh.rip_edge_edge_move", dict(), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def poly_build(): + return dict( + text="Poly Build", + icon="ops.mesh.polybuild_hover", + widget=None, + keymap=( + ("mesh.polybuild_face_at_cursor_move", + dict(TRANSFORM_OT_translate=dict(release_confirm=True)), + dict(type='ACTIONMOUSE', value='PRESS')), + ("mesh.polybuild_split_at_cursor_move", + dict(TRANSFORM_OT_translate=dict(release_confirm=True)), + dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)), + ("mesh.polybuild_dissolve_at_cursor", dict(), dict(type='ACTIONMOUSE', value='CLICK', alt=True)), + ("mesh.polybuild_hover", dict(use_boundary=False), dict(type='MOUSEMOVE', value='ANY', alt=True)), + ("mesh.polybuild_hover", dict(use_boundary=True), dict(type='MOUSEMOVE', value='ANY', any=True)), + ), + ) + + @ToolDef.from_fn + def edge_slide(): + return dict( + text="Edge Slide", + icon="ops.transform.edge_slide", + widget=None, + keymap=( + ("transform.edge_slide", dict(release_confirm=True), + dict(type='ACTIONMOUSE', value='PRESS') + ), + ), + ) + + @ToolDef.from_fn + def vert_slide(): + return dict( + text="Vertex Slide", + icon="ops.transform.vert_slide", + widget=None, + keymap=( + ("transform.vert_slide", dict(release_confirm=True), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def spin(): + return dict( + text="Spin", + icon="ops.mesh.spin", + widget=None, + keymap=( + ("mesh.spin", dict(), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def spin_duplicate(): + return dict( + text="Spin (Duplicate)", + icon="ops.mesh.spin.duplicate", + widget=None, + keymap=( + ("mesh.spin", dict(dupli=True), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def inset(): + def draw_settings(context, layout, tool): + wm = context.window_manager + props = tool.operator_properties("mesh.inset") + layout.prop(props, "use_outset") + layout.prop(props, "use_individual") + layout.prop(props, "use_even_offset") + layout.prop(props, "use_relative_offset") + + return dict( + text="Inset Faces", + icon="ops.mesh.inset", + widget=None, + keymap=( + ("mesh.inset", dict(release_confirm=True), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def bevel(): + return dict( + text="Bevel", + icon="ops.mesh.bevel", + widget=None, + keymap=( + ("mesh.bevel", dict(), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def extrude(): + return dict( + text="Extrude Region", + icon="ops.mesh.extrude_region_move", + widget="MESH_GGT_extrude", + operator="view3d.edit_mesh_extrude_move_normal", + keymap=( + ("mesh.extrude_context_move", dict(TRANSFORM_OT_translate=dict(release_confirm=True)), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def extrude_individual(): + return dict( + text="Extrude Individual", + icon="ops.mesh.extrude_faces_move", + widget=None, + keymap=( + ("mesh.extrude_faces_move", dict(TRANSFORM_OT_shrink_fatten=dict(release_confirm=True)), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def extrude_cursor(): + return dict( + text="Extrude to Cursor", + icon="ops.mesh.dupli_extrude_cursor", + widget=None, + keymap=( + ("mesh.dupli_extrude_cursor", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def loopcut_slide(): + return dict( + text="Loop Cut", + icon="ops.mesh.loopcut_slide", + widget=None, + keymap=( + ("mesh.loopcut_slide", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def offset_edge_loops_slide(): + return dict( + text="Offset Edge Loop Cut", + icon="ops.mesh.offset_edge_loops_slide", + widget=None, + keymap=( + ("mesh.offset_edge_loops_slide", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def vertex_smooth(): + return dict( + text="Smooth", + icon="ops.mesh.vertices_smooth", + widget=None, + keymap=( + ("mesh.vertices_smooth", dict(), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def vertex_randomize(): + return dict( + text="Randomize", + icon="ops.transform.vertex_random", + widget=None, + keymap=( + ("transform.vertex_random", dict(), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def shrink_fatten(): + def draw_settings(context, layout, tool): + wm = context.window_manager + props = tool.operator_properties("transform.shrink_fatten") + layout.prop(props, "use_even_offset") + + return dict( + text="Shrink/Fatten", + icon="ops.transform.shrink_fatten", + widget=None, + keymap=( + ("transform.shrink_fatten", dict(release_confirm=True), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def push_pull(): + return dict( + text="Push/Pull", + icon="ops.transform.push_pull", + widget=None, + keymap=( + ("transform.push_pull", dict(release_confirm=True), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def knife(): + def draw_settings(context, layout, tool): + wm = context.window_manager + props = tool.operator_properties("mesh.knife_tool") + layout.prop(props, "use_occlude_geometry") + layout.prop(props, "only_selected") + + return dict( + text="Knife", + icon="ops.mesh.knife_tool", + widget=None, + keymap=( + ("mesh.knife_tool", + dict(wait_for_input=False), + dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def bisect(): + return dict( + text="Bisect", + icon="ops.mesh.bisect", + widget=None, + keymap=( + ("mesh.bisect", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + +class _defs_edit_curve: + + @ToolDef.from_fn + def draw(): + def draw_settings(context, layout, tool): + # Tool settings initialize operator options. + tool_settings = context.tool_settings + cps = tool_settings.curve_paint_settings + + col = layout.row() + + col.prop(cps, "curve_type") + + if cps.curve_type == 'BEZIER': + col.prop(cps, "error_threshold") + col.prop(cps, "fit_method") + col.prop(cps, "use_corners_detect") + + col = layout.row() + col.active = cps.use_corners_detect + col.prop(cps, "corner_angle") + + return dict( + text="Draw", + cursor='PAINT_BRUSH', + icon=None, + widget=None, + keymap=( + ("curve.draw", dict(wait_for_input=False), dict(type='ACTIONMOUSE', value='PRESS')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def extrude_cursor(): + return dict( + text="Extrude Cursor", + icon=None, + widget=None, + keymap=( + ("curve.vertex_add", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + +class _defs_pose: + + @ToolDef.from_fn + def breakdown(): + return dict( + text="Breakdowner", + icon="ops.pose.breakdowner", + widget=None, + keymap=( + ("pose.breakdown", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def push(): + return dict( + text="Push", + icon="ops.pose.push", + widget=None, + keymap=( + ("pose.push", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def relax(): + return dict( + text="Relax", + icon="ops.pose.relax", + widget=None, + keymap=( + ("pose.relax", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + +class _defs_particle: + + @staticmethod + def generate_from_brushes(context): + return generate_from_enum_ex( + context, + icon_prefix="brush.particle.", + data=context.tool_settings.particle_edit, + attr="tool", + ) + + +class _defs_sculpt: + + @staticmethod + def generate_from_brushes(context): + return generate_from_brushes_ex( + context, + icon_prefix="brush.sculpt.", + brush_test_attr="use_paint_sculpt", + brush_category_attr="sculpt_tool", + brush_category_layout=( + ('DRAW',), + ('GRAB', 'THUMB'), + ('SNAKE_HOOK',), + ('BLOB', 'INFLATE'), + ('SMOOTH', 'SCRAPE', 'FLATTEN'), + ('CREASE', 'PINCH'), + ('CLAY', 'CLAY_STRIPS'), + ('LAYER',), + ('NUDGE', 'ROTATE'), + ('FILL',), + ('SIMPLIFY',), + ('MASK',), + ) + ) + + +class _defs_vertex_paint: + + @staticmethod + def generate_from_brushes(context): + return generate_from_brushes_ex( + context, + icon_prefix="brush.paint_vertex.", + brush_test_attr="use_paint_vertex", + brush_category_attr="vertex_tool", + brush_category_layout=( + ('MIX',), + ('BLUR', 'AVERAGE'), + ('SMEAR',), + ( + 'ADD', 'SUB', 'MUL', 'LIGHTEN', 'DARKEN', + 'COLORDODGE', 'DIFFERENCE', 'SCREEN', 'HARDLIGHT', + 'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY', + 'SATURATION', 'HUE', 'ERASE_ALPHA', 'ADD_ALPHA', + ), + ) + ) + + +class _defs_texture_paint: + + @staticmethod + def generate_from_brushes(context): + return generate_from_brushes_ex( + context, + icon_prefix="brush.paint_texture.", + brush_test_attr="use_paint_image", + brush_category_attr="image_tool", + brush_category_layout=( + ('DRAW',), + ('SOFTEN',), + ('SMEAR',), + ('CLONE',), + ('FILL',), + ('MASK',), + ) + ) + + +class _defs_weight_paint: + + @staticmethod + def generate_from_brushes(context): + return generate_from_brushes_ex( + context, + icon_prefix="brush.paint_weight.", + brush_test_attr="use_paint_weight", + brush_category_attr="vertex_tool", + brush_category_layout=( + ('MIX',), + ('BLUR', 'AVERAGE'), + ('SMEAR',), + ( + 'ADD', 'SUB', 'MUL', 'LIGHTEN', 'DARKEN', + 'COLORDODGE', 'DIFFERENCE', 'SCREEN', 'HARDLIGHT', + 'OVERLAY', 'SOFTLIGHT', 'EXCLUSION', 'LUMINOCITY', + 'SATURATION', 'HUE', + ), + ) + ) + + @ToolDef.from_fn + def sample_weight(): + return dict( + text="Sample Weight", + icon="ops.paint.weight_sample", + widget=None, + keymap=( + ("paint.weight_sample", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def sample_weight_group(): + return dict( + text="Sample Vertex Group", + icon="ops.paint.weight_sample_group", + widget=None, + keymap=( + ("paint.weight_sample_group", dict(), dict(type='ACTIONMOUSE', value='PRESS')), + ), + ) + + @ToolDef.from_fn + def gradient(): + def draw_settings(context, layout, tool): + wm = context.window_manager + props = tool.operator_properties("paint.weight_gradient") + layout.prop(props, "type") + + return dict( + text="Gradient", + icon="ops.paint.weight_gradient", + widget=None, + keymap=( + ("paint.weight_gradient", dict(), dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + +class _defs_uv_select: + + @ToolDef.from_fn + def border(): + return dict( + text="Select Border", + icon="ops.generic.select_border", + widget=None, + keymap=( + ("uv.select_border", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + # ("uv.select_border", + # dict(deselect=True), + # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def circle(): + return dict( + text="Select Circle", + icon="ops.generic.select_circle", + widget=None, + keymap=( + ("uv.select_circle", + dict(), # dict(deselect=False), + dict(type='ACTIONMOUSE', value='PRESS')), + # ("uv.select_circle", + # dict(deselect=True), + # dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def lasso(): + return dict( + text="Select Lasso", + icon="ops.generic.select_lasso", + widget=None, + keymap=( + ("uv.select_lasso", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + # ("uv.select_lasso", + # dict(deselect=True), + # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) + + +class _defs_gpencil_paint: + @classmethod + def draw_color_selector(cls, context, layout): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + ts = context.tool_settings + row = layout.row(align=True) + row.prop(ts, "use_gpencil_thumbnail_list", text="", icon="IMGDISPLAY") + if ts.use_gpencil_thumbnail_list is False: + row.template_ID(gp_settings, "material", live_icon=True) + else: + row.template_greasepencil_color(gp_settings, "material", rows=3, cols=8, scale=0.8) + + @classmethod + def draw_settings_common(cls, context, layout, tool): + ob = context.active_object + if ob and ob.mode == 'GPENCIL_PAINT': + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + tool_settings = context.tool_settings + + if gp_settings.gpencil_brush_type == 'ERASE': + row = layout.row() + row.prop(brush, "size", text="Radius") + elif gp_settings.gpencil_brush_type == 'FILL': + row = layout.row() + row.prop(gp_settings, "gpencil_fill_leak", text="Leak Size") + row.prop(brush, "size", text="Thickness") + row.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify") + + _defs_gpencil_paint.draw_color_selector(context, layout) + + row = layout.row(align=True) + row.prop(gp_settings, "gpencil_fill_draw_mode", text="") + row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID') + + else: # bgpsettings.gpencil_brush_type == 'DRAW': + row = layout.row(align=True) + row.prop(brush, "size", text="Radius") + row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE') + row = layout.row(align=True) + row.prop(gp_settings, "pen_strength", slider=True) + row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') + + _defs_gpencil_paint.draw_color_selector(context, layout) + + @staticmethod + def generate_from_brushes(context): + return generate_from_brushes_ex( + context, + icon_prefix="brush.gpencil.", + brush_test_attr="use_paint_grease_pencil", + brush_category_attr="grease_pencil_tool", + brush_category_layout=( + ('PENCIL',), + ('PEN',), + ('INK',), + ('INKNOISE',), + ('BLOCK',), + ('MARKER',), + ('FILL',), + ('SOFT',), + ('HARD',), + ('STROKE',), + ) + ) + + +class _defs_gpencil_edit: + @ToolDef.from_fn + def bend(): + return dict( + text="Bend", + icon="ops.gpencil.edit_bend", + widget=None, + keymap=( + ("transform.bend", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def mirror(): + return dict( + text="Mirror", + icon="ops.gpencil.edit_mirror", + widget=None, + keymap=( + ("transform.mirror", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def shear(): + return dict( + text="Shear", + icon="ops.gpencil.edit_shear", + widget=None, + keymap=( + ("transform.shear", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + @ToolDef.from_fn + def tosphere(): + return dict( + text="To Sphere", + icon="ops.gpencil.edit_to_sphere", + widget=None, + keymap=( + ("transform.tosphere", + dict(), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + ) + + +class _defs_gpencil_sculpt: + @classmethod + def draw_settings_common(cls, context, layout, tool): + ob = context.active_object + if ob and ob.mode == 'GPENCIL_SCULPT': + ts = context.tool_settings + settings = ts.gpencil_sculpt + brush = settings.brush + + layout.prop(brush, "size", slider=True) + + row = layout.row(align=True) + row.prop(brush, "strength", slider=True) + row.prop(brush, "use_pressure_strength", text="") + row.separator() + row.prop(ts.gpencil_sculpt, "use_select_mask", text="") + + @ToolDef.from_fn + def smooth(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Smooth", + icon="ops.gpencil.sculpt_smooth", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='SMOOTH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def thickness(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Thickness", + icon="ops.gpencil.sculpt_thickness", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='THICKNESS', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def strength(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Strength", + icon="ops.gpencil.sculpt_strength", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='STRENGTH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def grab(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Grab", + icon="ops.gpencil.sculpt_grab", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='GRAB', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def push(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Push", + icon="ops.gpencil.sculpt_push", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='PUSH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def twist(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Twist", + icon="ops.gpencil.sculpt_twist", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='TWIST', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def pinch(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Pinch", + icon="ops.gpencil.sculpt_pinch", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='PINCH', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def randomize(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Randomize", + icon="ops.gpencil.sculpt_randomize", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='RANDOMIZE', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + @ToolDef.from_fn + def clone(): + def draw_settings(context, layout, tool): + _defs_gpencil_sculpt.draw_settings_common(context, layout, tool) + + return dict( + text="Clone", + icon="ops.gpencil.sculpt_clone", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='CLONE', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + +class _defs_gpencil_weight: + @classmethod + def draw_settings_common(cls, context, layout, tool): + ob = context.active_object + if ob and ob.mode == 'GPENCIL_WEIGHT': + settings = context.tool_settings.gpencil_sculpt + brush = settings.brush + + layout.prop(brush, "size", slider=True) + + row = layout.row(align=True) + row.prop(brush, "strength", slider=True) + row.prop(brush, "use_pressure_strength", text="") + + @ToolDef.from_fn + def paint(): + def draw_settings(context, layout, tool): + _defs_gpencil_weight.draw_settings_common(context, layout, tool) + + return dict( + text="Draw", + icon="ops.gpencil.sculpt_weight", + widget=None, + keymap=( + ("gpencil.brush_paint", + dict(mode='WEIGHT', wait_for_input=False), + dict(type='EVT_TWEAK_A', value='ANY')), + ), + draw_settings=draw_settings, + ) + + +class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel): + bl_space_type = 'IMAGE_EDITOR' + bl_region_type = 'TOOLS' + bl_category = "Tools" + bl_label = "Tools" # not visible + bl_options = {'HIDE_HEADER'} + + # Satisfy the 'ToolSelectPanelHelper' API. + keymap_prefix = "Image Editor Tool:" + + @classmethod + def tools_from_context(cls, context, mode=None): + if mode is None: + mode = context.space_data.mode + for tools in (cls._tools[None], cls._tools.get(mode, ())): + for item in tools: + if not (type(item) is ToolDef) and callable(item): + yield from item(context) + else: + yield item + + @classmethod + def tools_all(cls): + yield from cls._tools.items() + + # for reuse + _tools_select = ( + ( + _defs_uv_select.border, + _defs_uv_select.circle, + _defs_uv_select.lasso, + ), + ) + + _tools = { + None: [ + # for all modes + ], + 'VIEW': [ + *_tools_select, + + ], + 'MASK': [ + None, + ], + 'PAINT': [ + _defs_texture_paint.generate_from_brushes, + ], + } + + +class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'TOOLS' + bl_category = "Tools" + bl_label = "Tools" # not visible + bl_options = {'HIDE_HEADER'} + + # Satisfy the 'ToolSelectPanelHelper' API. + keymap_prefix = "3D View Tool:" + + @classmethod + def tools_from_context(cls, context, mode=None): + if mode is None: + mode = context.mode + for tools in (cls._tools[None], cls._tools.get(mode, ())): + for item in tools: + if not (type(item) is ToolDef) and callable(item): + yield from item(context) + else: + yield item + + @classmethod + def tools_all(cls): + yield from cls._tools.items() + + # for reuse + _tools_transform = ( + _defs_transform.transform, + _defs_transform.translate, + _defs_transform.rotate, + ( + _defs_transform.scale, + _defs_transform.scale_cage, + ), + ) + + _tools_select = ( + ( + _defs_view3d_select.border, + _defs_view3d_select.circle, + _defs_view3d_select.lasso, + ), + ) + + _tools_annotate = ( + ( + _defs_annotate.scribble, + _defs_annotate.line, + _defs_annotate.poly, + _defs_annotate.eraser, + ), + _defs_view3d_generic.ruler, + ) + + _tools = { + None: [ + _defs_view3d_generic.cursor, + # End group. + ], + 'OBJECT': [ + *_tools_select, + None, + *_tools_transform, + None, + *_tools_annotate, + ], + 'POSE': [ + *_tools_select, + *_tools_transform, + None, + *_tools_annotate, + None, + ( + _defs_pose.breakdown, + _defs_pose.push, + _defs_pose.relax, + ), + ], + 'EDIT_ARMATURE': [ + *_tools_select, + None, + *_tools_transform, + None, + *_tools_annotate, + _defs_edit_armature.roll, + ( + _defs_edit_armature.bone_size, + _defs_edit_armature.bone_envelope, + ), + None, + ( + _defs_edit_armature.extrude, + _defs_edit_armature.extrude_cursor, + ), + ], + 'EDIT_MESH': [ + *_tools_select, + None, + *_tools_transform, + None, + *_tools_annotate, + None, + _defs_edit_mesh.cube_add, + None, + ( + _defs_edit_mesh.extrude, + _defs_edit_mesh.extrude_individual, + _defs_edit_mesh.extrude_cursor, + ), + _defs_edit_mesh.inset, + _defs_edit_mesh.bevel, + ( + _defs_edit_mesh.loopcut_slide, + _defs_edit_mesh.offset_edge_loops_slide, + ), + ( + _defs_edit_mesh.knife, + _defs_edit_mesh.bisect, + ), + _defs_edit_mesh.poly_build, + ( + _defs_edit_mesh.spin, + _defs_edit_mesh.spin_duplicate, + ), + ( + _defs_edit_mesh.vertex_smooth, + _defs_edit_mesh.vertex_randomize, + ), + ( + _defs_edit_mesh.edge_slide, + _defs_edit_mesh.vert_slide, + ), + ( + _defs_edit_mesh.shrink_fatten, + _defs_edit_mesh.push_pull, + ), + ( + _defs_edit_mesh.rip_region, + _defs_edit_mesh.rip_edge, + ), + ], + 'EDIT_CURVE': [ + *_tools_select, + None, + *_tools_transform, + None, + *_tools_annotate, + None, + _defs_edit_curve.draw, + _defs_edit_curve.extrude_cursor, + ], + 'PARTICLE': [ + _defs_particle.generate_from_brushes, + ], + 'SCULPT': [ + _defs_sculpt.generate_from_brushes, + ], + 'PAINT_TEXTURE': [ + _defs_texture_paint.generate_from_brushes, + ], + 'PAINT_VERTEX': [ + _defs_vertex_paint.generate_from_brushes, + ], + 'PAINT_WEIGHT': [ + _defs_weight_paint.generate_from_brushes, + None, + _defs_weight_paint.sample_weight, + _defs_weight_paint.sample_weight_group, + None, + # TODO, override brush events + *_tools_select, + None, + _defs_weight_paint.gradient, + ], + 'GPENCIL_PAINT': [ + _defs_gpencil_paint.generate_from_brushes, + ], + 'GPENCIL_EDIT': [ + *_tools_select, + None, + *_tools_transform, + None, + _defs_gpencil_edit.bend, + _defs_gpencil_edit.mirror, + _defs_gpencil_edit.shear, + _defs_gpencil_edit.tosphere, + ], + 'GPENCIL_SCULPT': [ + _defs_gpencil_sculpt.smooth, + _defs_gpencil_sculpt.thickness, + _defs_gpencil_sculpt.strength, + _defs_gpencil_sculpt.grab, + _defs_gpencil_sculpt.push, + _defs_gpencil_sculpt.twist, + _defs_gpencil_sculpt.pinch, + _defs_gpencil_sculpt.randomize, + _defs_gpencil_sculpt.clone, + ], + 'GPENCIL_WEIGHT': [ + _defs_gpencil_weight.paint, + ], + } + + +classes = ( + IMAGE_PT_tools_active, + VIEW3D_PT_tools_active, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py new file mode 100644 index 00000000000..a417ef856f9 --- /dev/null +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -0,0 +1,641 @@ +# ##### 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> +import bpy +from bpy.types import Header, Menu, Panel + + +class TOPBAR_HT_upper_bar(Header): + bl_space_type = 'TOPBAR' + + def draw(self, context): + region = context.region + + if region.alignment == 'RIGHT': + self.draw_right(context) + else: + self.draw_left(context) + + def draw_left(self, context): + layout = self.layout + + window = context.window + screen = context.screen + + layout.operator("wm.splash", text="", icon='BLENDER', emboss=False) + + INFO_MT_editor_menus.draw_collapsible(context, layout) + + layout.separator() + + if not screen.show_fullscreen: + layout.template_ID_tabs( + window, "workspace", + new="workspace.workspace_add_menu", + unlink="workspace.workspace_delete", + ) + else: + layout.operator( + "screen.back_to_previous", + icon='SCREEN_BACK', + text="Back to Previous", + ) + + def draw_right(self, context): + layout = self.layout + + window = context.window + scene = window.scene + + # Active workspace view-layer is retrieved through window, not through workspace. + layout.template_ID(window, "scene", new="scene.new", unlink="scene.delete") + + row = layout.row(align=True) + row.template_search( + window, "view_layer", + scene, "view_layers", + new="scene.view_layer_add", + unlink="scene.view_layer_remove") + + +class TOPBAR_HT_lower_bar(Header): + bl_space_type = 'TOPBAR' + bl_region_type = 'WINDOW' + + def draw(self, context): + layout = self.layout + region = context.region + + if region.alignment == 'LEFT': + self.draw_left(context) + elif region.alignment == 'RIGHT': + self.draw_right(context) + else: + self.draw_center(context) + + def draw_left(self, context): + layout = self.layout + mode = context.mode + + # Active Tool + # ----------- + from .space_toolsystem_common import ToolSelectPanelHelper + ToolSelectPanelHelper.draw_active_tool_header(context, layout) + + # Object Mode Options + # ------------------- + + # Example of how toolsettings can be accessed as pop-overs. + + # TODO(campbell): editing options should be after active tool options + # (obviously separated for from the users POV) + draw_fn = getattr(_draw_left_context_mode, mode, None) + if draw_fn is not None: + draw_fn(context, layout) + + # Note: general mode options should be added to 'draw_right'. + if mode == 'SCULPT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="") + elif mode == 'PAINT_VERTEX': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="") + elif mode == 'PAINT_WEIGHT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="") + elif mode == 'PAINT_TEXTURE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="") + elif mode == 'EDIT_ARMATURE': + pass + elif mode == 'EDIT_CURVE': + pass + elif mode == 'EDIT_MESH': + pass + elif mode == 'POSE': + pass + elif mode == 'PARTICLE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="") + elif mode == 'GPENCIL_PAINT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_paint", category="") + + def draw_center(self, context): + pass + + def draw_right(self, context): + layout = self.layout + + # General options, note, these _could_ display at the RHS of the draw_left callback. + # we just want them not to be confused with tool options. + mode = context.mode + + if mode == 'SCULPT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".sculpt_mode", category="") + elif mode == 'PAINT_VERTEX': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".vertexpaint", category="") + elif mode == 'PAINT_WEIGHT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".weightpaint", category="") + elif mode == 'PAINT_TEXTURE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".imagepaint", category="") + elif mode == 'EDIT_TEXT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".text_edit", category="") + elif mode == 'EDIT_ARMATURE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".armature_edit", category="") + elif mode == 'EDIT_METABALL': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mball_edit", category="") + elif mode == 'EDIT_LATTICE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".lattice_edit", category="") + elif mode == 'EDIT_CURVE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".curve_edit", category="") + elif mode == 'EDIT_MESH': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mesh_edit", category="") + elif mode == 'POSE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".posemode", category="") + elif mode == 'PARTICLE': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".particlemode", category="") + elif mode == 'OBJECT': + layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".objectmode", category="") + elif mode == 'GPENCIL_PAINT': + layout.prop(context.tool_settings, "gpencil_stroke_placement_view3d", text='') + if context.tool_settings.gpencil_stroke_placement_view3d in ('ORIGIN', 'CURSOR'): + layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='') + layout.prop(context.tool_settings, "use_gpencil_draw_onback", text="", icon='ORTHO') + layout.prop(context.tool_settings, "use_gpencil_additive_drawing", text="", icon='FREEZE') + + elif mode == 'GPENCIL_SCULPT': + layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='') + + +class _draw_left_context_mode: + @staticmethod + def SCULPT(context, layout): + brush = context.tool_settings.sculpt.brush + if brush is None: + return + + from .properties_paint_common import UnifiedPaintPanel + + UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius") + UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength") + layout.prop(brush, "direction", text="", expand=True) + + def PAINT_TEXTURE(context, layout): + brush = context.tool_settings.vertex_paint.brush + if brush is None: + return + + from .properties_paint_common import UnifiedPaintPanel + + layout.prop(brush, "color", text="") + UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius") + UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength") + + def PAINT_VERTEX(context, layout): + brush = context.tool_settings.vertex_paint.brush + if brush is None: + return + + from .properties_paint_common import UnifiedPaintPanel + + layout.prop(brush, "color", text="") + UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius") + UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength") + + def PAINT_WEIGHT(context, layout): + brush = context.tool_settings.weight_paint.brush + if brush is None: + return + + from .properties_paint_common import UnifiedPaintPanel + + UnifiedPaintPanel.prop_unified_weight(layout, context, brush, "weight", slider=True, text="Weight") + UnifiedPaintPanel.prop_unified_size(layout, context, brush, "size", slider=True, text="Radius") + UnifiedPaintPanel.prop_unified_strength(layout, context, brush, "strength", slider=True, text="Strength") + + def PARTICLE(context, layout): + # See: 'VIEW3D_PT_tools_brush', basically a duplicate + settings = context.tool_settings.particle_edit + brush = settings.brush + tool = settings.tool + if tool != 'NONE': + layout.prop(brush, "size", slider=True) + if tool == 'ADD': + layout.prop(brush, "count") + else: + layout.prop(brush, "strength", slider=True) + + if tool == 'ADD': + layout.prop(settings, "use_default_interpolate") + layout.prop(brush, "steps", slider=True) + layout.prop(settings, "default_key_count", slider=True) + elif tool == 'LENGTH': + layout.row().prop(brush, "length_mode", expand=True) + elif tool == 'PUFF': + layout.row().prop(brush, "puff_mode", expand=True) + layout.prop(brush, "use_puff_volume") + +class INFO_MT_editor_menus(Menu): + bl_idname = "INFO_MT_editor_menus" + bl_label = "" + + def draw(self, context): + self.draw_menus(self.layout, context) + + @staticmethod + def draw_menus(layout, context): + layout.menu("INFO_MT_file") + layout.menu("INFO_MT_edit") + + layout.menu("INFO_MT_render") + + layout.menu("INFO_MT_window") + layout.menu("INFO_MT_help") + + +class INFO_MT_file(Menu): + bl_label = "File" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.read_homefile", text="New", icon='NEW') + layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER') + layout.menu("INFO_MT_file_open_recent") + layout.operator("wm.revert_mainfile") + layout.operator("wm.recover_last_session") + layout.operator("wm.recover_auto_save", text="Recover Auto Save...") + + layout.separator() + + layout.operator_context = 'EXEC_AREA' if context.blend_data.is_saved else 'INVOKE_AREA' + layout.operator("wm.save_mainfile", text="Save", icon='FILE_TICK') + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.save_as_mainfile", text="Save As...") + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.save_as_mainfile", text="Save Copy...").copy = True + + layout.separator() + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.save_homefile") + layout.operator("wm.read_factory_settings") + + layout.separator() + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.link", text="Link...", icon='LINK_BLEND') + layout.operator("wm.append", text="Append...", icon='APPEND_BLEND') + layout.menu("INFO_MT_file_previews") + + layout.separator() + + layout.menu("INFO_MT_file_import", icon='IMPORT') + layout.menu("INFO_MT_file_export", icon='EXPORT') + + layout.separator() + + layout.menu("INFO_MT_file_external_data") + + layout.separator() + + layout.operator_context = 'EXEC_AREA' + if bpy.data.is_dirty and context.user_preferences.view.use_quit_dialog: + layout.operator_context = 'INVOKE_SCREEN' # quit dialog + layout.operator("wm.quit_blender", text="Quit", icon='QUIT') + + +class INFO_MT_file_import(Menu): + bl_idname = "INFO_MT_file_import" + bl_label = "Import" + + def draw(self, context): + if bpy.app.build_options.collada: + self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)") + if bpy.app.build_options.alembic: + self.layout.operator("wm.alembic_import", text="Alembic (.abc)") + + +class INFO_MT_file_export(Menu): + bl_idname = "INFO_MT_file_export" + bl_label = "Export" + + def draw(self, context): + if bpy.app.build_options.collada: + self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)") + if bpy.app.build_options.alembic: + self.layout.operator("wm.alembic_export", text="Alembic (.abc)") + + +class INFO_MT_file_external_data(Menu): + bl_label = "External Data" + + def draw(self, context): + layout = self.layout + + icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT' + layout.operator("file.autopack_toggle", icon=icon) + + layout.separator() + + pack_all = layout.row() + pack_all.operator("file.pack_all") + pack_all.active = not bpy.data.use_autopack + + unpack_all = layout.row() + unpack_all.operator("file.unpack_all") + unpack_all.active = not bpy.data.use_autopack + + layout.separator() + + layout.operator("file.make_paths_relative") + layout.operator("file.make_paths_absolute") + layout.operator("file.report_missing_files") + layout.operator("file.find_missing_files") + + +class INFO_MT_file_previews(Menu): + bl_label = "Data Previews" + + def draw(self, context): + layout = self.layout + + layout.operator("wm.previews_ensure") + layout.operator("wm.previews_batch_generate") + + layout.separator() + + layout.operator("wm.previews_clear") + layout.operator("wm.previews_batch_clear") + + +class INFO_MT_game(Menu): + bl_label = "Game" + + def draw(self, context): + layout = self.layout + + gs = context.scene.game_settings + + layout.operator("view3d.game_start") + + layout.separator() + + layout.prop(gs, "show_debug_properties") + layout.prop(gs, "show_framerate_profile") + layout.prop(gs, "show_physics_visualization") + layout.prop(gs, "use_deprecation_warnings") + layout.prop(gs, "use_animation_record") + layout.separator() + layout.prop(gs, "use_auto_start") + + +class INFO_MT_render(Menu): + bl_label = "Render" + + def draw(self, context): + layout = self.layout + + rd = context.scene.render + + layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True + props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION') + props.animation = True + props.use_viewport = True + + layout.separator() + + layout.operator("sound.mixdown", text="Render Audio...") + + layout.separator() + + layout.operator("render.view_show", text="View Render") + layout.operator("render.play_rendered_anim", text="View Animation") + layout.prop_menu_enum(rd, "display_mode", text="Display Mode") + + layout.separator() + + layout.prop(rd, "use_lock_interface", text="Lock Interface") + + +class INFO_MT_opengl_render(Menu): + bl_label = "OpenGL Render Options" + + def draw(self, context): + layout = self.layout + + rd = context.scene.render + layout.prop(rd, "use_antialiasing") + layout.prop(rd, "use_full_sample") + + layout.prop_menu_enum(rd, "antialiasing_samples") + layout.prop_menu_enum(rd, "alpha_mode") + + +class INFO_MT_edit(Menu): + bl_label = "Edit" + + def draw(self, context): + layout = self.layout + + layout.operator("ed.undo") + layout.operator("ed.redo") + + layout.separator() + + layout.operator("ed.undo_history", text="Undo History...") + + layout.separator() + + layout.operator("screen.repeat_last") + layout.operator("screen.repeat_history", text="Repeat History...") + + layout.separator() + + layout.operator("screen.redo_last", text="Adjust Last Operation...") + + layout.separator() + + layout.operator("wm.search_menu", text="Operator Search...") + + layout.separator() + + # Should move elsewhere (impacts outliner & 3D view). + tool_settings = context.tool_settings + layout.prop(tool_settings, "lock_object_mode") + + layout.separator() + + layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES') + + +class INFO_MT_window(Menu): + bl_label = "Window" + + def draw(self, context): + import sys + + layout = self.layout + + layout.operator("wm.window_new") + layout.operator("wm.window_new_main") + + layout.separator() + + layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER') + + layout.separator() + + layout.operator("screen.workspace_cycle", text="Next Workspace").direction = 'NEXT' + layout.operator("screen.workspace_cycle", text="Previous Workspace").direction = 'PREV' + + layout.separator() + + layout.operator("screen.screenshot") + + if sys.platform[:3] == "win": + layout.separator() + layout.operator("wm.console_toggle", icon='CONSOLE') + + if context.scene.render.use_multiview: + layout.separator() + layout.operator("wm.set_stereo_3d") + + +class INFO_MT_help(Menu): + bl_label = "Help" + + def draw(self, context): + layout = self.layout + + show_developer = context.user_preferences.view.show_developer_ui + + layout.operator( + "wm.url_open", text="Manual", icon='HELP', + ).url = "https://docs.blender.org/manual/en/dev/" + + layout.operator( + "wm.url_open", text="Report a Bug", icon='URL', + ).url = "https://developer.blender.org/maniphest/task/edit/form/1" + + layout.separator() + + layout.operator( + "wm.url_open", text="User Communities", icon='URL', + ).url = "https://www.blender.org/community/" + layout.operator( + "wm.url_open", text="Developer Community", icon='URL', + ).url = "https://www.blender.org/get-involved/developers/" + + layout.separator() + + layout.operator( + "wm.url_open", text="Blender Website", icon='URL', + ).url = "https://www.blender.org" + layout.operator( + "wm.url_open", text="Blender Store", icon='URL', + ).url = "https://store.blender.org" + + layout.operator( + "wm.url_open", text="Release Notes", icon='URL', + ).url = "https://www.blender.org/download/releases/%d-%d/" % bpy.app.version[:2] + + layout.separator() + + if show_developer: + layout.operator( + "wm.url_open", text="Python API Reference", icon='URL', + ).url = bpy.types.WM_OT_doc_view._prefix + + layout.operator("wm.operator_cheat_sheet", icon='TEXT') + + layout.operator("wm.sysinfo") + + layout.separator() + + layout.operator("wm.splash", icon='BLENDER') + + +class TOPBAR_MT_file_specials(Menu): + bl_label = "File Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_AREA' + layout.operator("wm.read_homefile", text="New", icon='NEW') + layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER') + + layout.separator() + + layout.operator("wm.link", text="Link...", icon='LINK_BLEND') + layout.operator("wm.append", text="Append...", icon='APPEND_BLEND') + + layout.separator() + + layout.menu("INFO_MT_file_import", icon='IMPORT') + layout.menu("INFO_MT_file_export", icon='EXPORT') + + +class TOPBAR_MT_window_specials(Menu): + bl_label = "Window Context Menu" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'EXEC_AREA' + + layout.operator("wm.window_new") + layout.operator("wm.window_new_main") + + layout.operator_context = 'INVOKE_AREA' + + layout.operator("screen.area_dupli") + + layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER') + + layout.separator() + + layout.operator("screen.area_split", text="Horizontal Split").direction = 'HORIZONTAL' + layout.operator("screen.area_split", text="Vertical Split").direction = 'VERTICAL' + + layout.separator() + + layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES') + + +classes = ( + TOPBAR_HT_upper_bar, + TOPBAR_HT_lower_bar, + TOPBAR_MT_file_specials, + TOPBAR_MT_window_specials, + INFO_MT_editor_menus, + INFO_MT_file, + INFO_MT_file_import, + INFO_MT_file_export, + INFO_MT_file_external_data, + INFO_MT_file_previews, + INFO_MT_edit, + INFO_MT_game, + INFO_MT_render, + INFO_MT_window, + INFO_MT_help, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index e0902dd8636..52d4640806d 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -22,37 +22,20 @@ from bpy.types import ( Header, Menu, Panel, + Operator, ) from bpy.app.translations import pgettext_iface as iface_ from bpy.app.translations import contexts as i18n_contexts -def opengl_lamp_buttons(column, lamp): - split = column.row() - - split.prop(lamp, "use", text="", icon='OUTLINER_OB_LAMP' if lamp.use else 'LAMP_DATA') - - col = split.column() - col.active = lamp.use - row = col.row() - row.label(text="Diffuse:") - row.prop(lamp, "diffuse_color", text="") - row = col.row() - row.label(text="Specular:") - row.prop(lamp, "specular_color", text="") - - col = split.column() - col.active = lamp.use - col.prop(lamp, "direction", text="") - - class USERPREF_HT_header(Header): bl_space_type = 'USER_PREFERENCES' def draw(self, context): layout = self.layout - layout.template_header() + # No need to show type selector. + # layout.template_header() userpref = context.user_preferences @@ -61,13 +44,19 @@ class USERPREF_HT_header(Header): layout.operator_context = 'INVOKE_DEFAULT' - if userpref.active_section == 'INPUT': + if userpref.active_section == 'INTERFACE': + layout.operator("wm.save_workspace_file") + elif userpref.active_section == 'INPUT': layout.operator("wm.keyconfig_import") layout.operator("wm.keyconfig_export") elif userpref.active_section == 'ADDONS': layout.operator("wm.addon_install", icon='FILESEL') layout.operator("wm.addon_refresh", icon='FILE_REFRESH') layout.menu("USERPREF_MT_addons_online_resources") + elif userpref.active_section == 'LIGHTS': + layout.operator('wm.studiolight_install', text="Install MatCap").orientation = 'MATCAP' + layout.operator('wm.studiolight_install', text="Install World HDRI").orientation = 'WORLD' + layout.operator('wm.studiolight_install', text="Install Camera HDRI").orientation = 'CAMERA' elif userpref.active_section == 'THEMES': layout.operator("ui.reset_default_theme") layout.operator("wm.theme_install") @@ -222,41 +211,55 @@ class USERPREF_PT_interface(Panel): col.prop(view, "ui_scale", text="Scale") col.prop(view, "ui_line_width", text="Line Width") col.prop(view, "show_tooltips") - col.prop(view, "show_tooltips_python") - col.prop(view, "show_developer_ui") col.prop(view, "show_object_info", text="Object Info") col.prop(view, "show_large_cursors") col.prop(view, "show_view_name", text="View Name") col.prop(view, "show_playback_fps", text="Playback FPS") - col.prop(view, "use_global_scene") col.prop(view, "object_origin_size") col.separator() - col.separator() - col.separator() - col.prop(view, "show_mini_axis", text="Display Mini Axis") - sub = col.column() - sub.active = view.show_mini_axis + # col.prop(view, "show_gizmo_navigate") + + sub = col.column(align=True) + + sub.label("3D Viewport Axis:") + sub.row().prop(view, "mini_axis_type", expand=True) + + sub = col.column(align=True) + sub.active = view.mini_axis_type == 'MINIMAL' sub.prop(view, "mini_axis_size", text="Size") sub.prop(view, "mini_axis_brightness", text="Brightness") col.separator() - col.label("Warnings") - col.prop(view, "use_quit_dialog") + # Toolbox doesn't exist yet + # col.label(text="Toolbox:") + #col.prop(view, "show_column_layout") + #col.label(text="Open Toolbox Delay:") + #col.prop(view, "open_left_mouse_delay", text="Hold LMB") + #col.prop(view, "open_right_mouse_delay", text="Hold RMB") + col.prop(view, "show_gizmo", text="Gizmos") + sub = col.column() + sub.active = view.show_gizmo + sub.prop(view, "gizmo_size", text="Size") + + col.separator() + + col.label("Development:") + col.prop(view, "show_tooltips_python") + col.prop(view, "show_developer_ui") row.separator() row.separator() col = row.column() - col.label(text="View Manipulation:") + col.label(text="View Gizmos:") col.prop(view, "use_mouse_depth_cursor") col.prop(view, "use_cursor_lock_adjust") col.prop(view, "use_mouse_depth_navigate") col.prop(view, "use_zoom_to_mouse") col.prop(view, "use_rotate_around_active") - col.prop(view, "use_global_pivot") col.prop(view, "use_camera_lock_parent") col.separator() @@ -281,22 +284,6 @@ class USERPREF_PT_interface(Panel): row.separator() col = row.column() - # Toolbox doesn't exist yet - # col.label(text="Toolbox:") - #col.prop(view, "show_column_layout") - #col.label(text="Open Toolbox Delay:") - #col.prop(view, "open_left_mouse_delay", text="Hold LMB") - #col.prop(view, "open_right_mouse_delay", text="Hold RMB") - col.prop(view, "show_manipulator") - sub = col.column() - sub.active = view.show_manipulator - sub.prop(view, "manipulator_size", text="Size") - sub.prop(view, "manipulator_handle_size", text="Handle Size") - sub.prop(view, "manipulator_hotspot", text="Hotspot") - - col.separator() - col.separator() - col.separator() col.label(text="Menus:") col.prop(view, "use_mouse_over_open") @@ -317,6 +304,10 @@ class USERPREF_PT_interface(Panel): col.separator() col.prop(view, "show_splash") + + col.label("Warnings:") + col.prop(view, "use_quit_dialog") + col.separator() col.label(text="App Template:") @@ -370,14 +361,16 @@ class USERPREF_PT_edit(Panel): row.separator() col = row.column() - col.label(text="Grease Pencil:") + col.label(text="Annotations:") + sub = col.row() + sub.prop(edit, "grease_pencil_default_color", text="Default Color") col.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius") col.separator() + col.label(text="Grease Pencil/Annotations:") + col.separator() col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance") col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance") col.separator() - col.prop(edit, "grease_pencil_default_color", text="Default Color") - col.separator() col.prop(edit, "use_grease_pencil_simplify_stroke", text="Simplify Stroke") col.separator() col.separator() @@ -424,6 +417,7 @@ class USERPREF_PT_edit(Panel): col.label(text="Transform:") col.prop(edit, "use_drag_immediately") + col.prop(edit, "use_numeric_input_advanced") row.separator() row.separator() @@ -442,7 +436,7 @@ class USERPREF_PT_edit(Panel): col.prop(edit, "use_duplicate_text", text="Text") col.prop(edit, "use_duplicate_metaball", text="Metaball") col.prop(edit, "use_duplicate_armature", text="Armature") - col.prop(edit, "use_duplicate_lamp", text="Lamp") + col.prop(edit, "use_duplicate_light", text="Light") col.prop(edit, "use_duplicate_material", text="Material") col.prop(edit, "use_duplicate_texture", text="Texture") #col.prop(edit, "use_duplicate_fcurve", text="F-Curve") @@ -477,7 +471,6 @@ class USERPREF_PT_system(Panel): col = colsplit.column() col.label(text="General:") - col.prop(system, "frame_server_port") col.prop(system, "scrollback", text="Console Scrollback") col.separator() @@ -511,24 +504,21 @@ class USERPREF_PT_system(Panel): col = colsplit.column() col.label(text="OpenGL:") col.prop(system, "gl_clip_alpha", slider=True) - col.prop(system, "use_mipmaps") col.prop(system, "use_gpu_mipmap") col.prop(system, "use_16bit_textures") col.separator() - col.label(text="Selection") + col.label(text="Selection:") col.prop(system, "select_method", text="") col.prop(system, "use_select_pick_depth") col.separator() - col.label(text="Anisotropic Filtering") + col.label(text="Anisotropic Filtering:") col.prop(system, "anisotropic_filter", text="") col.separator() - col.label(text="Window Draw Method:") - col.prop(system, "window_draw_method", text="") col.prop(system, "multi_sample", text="") if sys.platform == "linux" and system.multi_sample != 'NONE': col.label(text="Might fail for Mesh editing selection!") @@ -536,49 +526,37 @@ class USERPREF_PT_system(Panel): col.prop(system, "use_region_overlap") col.separator() + col.prop(system, "gpu_viewport_quality") + + col.separator() + col.label(text="Grease Pencil Options:") + col.prop(system, "gpencil_multi_sample", text="") + col.separator() col.label(text="Text Draw Options:") col.prop(system, "use_text_antialiasing") if system.use_text_antialiasing: col.prop(system, "use_text_hinting") - col.separator() - - col.label(text="Textures:") - col.prop(system, "gl_texture_limit", text="Limit Size") - col.prop(system, "texture_time_out", text="Time Out") - col.prop(system, "texture_collection_rate", text="Collection Rate") - - col.separator() - - col.label(text="Images Draw Method:") - col.prop(system, "image_draw_method", text="") - - col.separator() - - col.label(text="Sequencer/Clip Editor:") - # currently disabled in the code - # col.prop(system, "prefetch_frames") - col.prop(system, "memory_cache_limit") - # 3. Column column = split.column() - column.label(text="Solid OpenGL Lights:") + column.label(text="Textures:") + column.prop(system, "gl_texture_limit", text="Limit Size") + column.prop(system, "texture_time_out", text="Time Out") + column.prop(system, "texture_collection_rate", text="Collection Rate") - split = column.split(percentage=0.1) - split.label() - split.label(text="Colors:") - split.label(text="Direction:") + column.separator() - lamp = system.solid_lights[0] - opengl_lamp_buttons(column, lamp) + column.label(text="Images Draw Method:") + column.prop(system, "image_draw_method", text="") - lamp = system.solid_lights[1] - opengl_lamp_buttons(column, lamp) + column.separator() - lamp = system.solid_lights[2] - opengl_lamp_buttons(column, lamp) + column.label(text="Sequencer/Clip Editor:") + # currently disabled in the code + # column.prop(system, "prefetch_frames") + column.prop(system, "memory_cache_limit") column.separator() @@ -720,6 +698,7 @@ class USERPREF_PT_theme(Panel): colsub.row().prop(widget_style, "item", slider=True) colsub.row().prop(widget_style, "inner", slider=True) colsub.row().prop(widget_style, "inner_sel", slider=True) + colsub.row().prop(widget_style, "roundness") subsplit = row.split(percentage=0.85) @@ -799,6 +778,9 @@ class USERPREF_PT_theme(Panel): col.label(text="Tool:") self._theme_widget_style(col, ui.wcol_tool) + col.label(text="Toolbar Item:") + self._theme_widget_style(col, ui.wcol_toolbar_item) + col.label(text="Radio Buttons:") self._theme_widget_style(col, ui.wcol_radio) @@ -847,6 +829,9 @@ class USERPREF_PT_theme(Panel): col.label(text="List Item:") self._theme_widget_style(col, ui.wcol_list_item) + col.label(text="Tab:") + self._theme_widget_style(col, ui.wcol_tab) + ui_state = theme.user_interface.wcol_state col.label(text="State:") @@ -861,6 +846,7 @@ class USERPREF_PT_theme(Panel): colsub.row().prop(ui_state, "inner_anim_sel") colsub.row().prop(ui_state, "inner_driven") colsub.row().prop(ui_state, "inner_driven_sel") + colsub.row().prop(ui_state, "blend") subsplit = row.split(percentage=0.85) @@ -869,7 +855,8 @@ class USERPREF_PT_theme(Panel): colsub = padding.column() colsub.row().prop(ui_state, "inner_key") colsub.row().prop(ui_state, "inner_key_sel") - colsub.row().prop(ui_state, "blend") + colsub.row().prop(ui_state, "inner_overridden") + colsub.row().prop(ui_state, "inner_overridden_sel") col.separator() col.separator() @@ -884,34 +871,22 @@ class USERPREF_PT_theme(Panel): colsub = padding.column() colsub = padding.column() colsub.row().prop(ui, "menu_shadow_fac") - - subsplit = row.split(percentage=0.85) - - padding = subsplit.split(percentage=0.15) - colsub = padding.column() - colsub = padding.column() - colsub.row().prop(ui, "menu_shadow_width") - - row = col.row() - - subsplit = row.split(percentage=0.95) - - padding = subsplit.split(percentage=0.15) - colsub = padding.column() - colsub = padding.column() colsub.row().prop(ui, "icon_alpha") + colsub.row().prop(ui, "icon_saturation") + colsub.row().prop(ui, "editor_outline") subsplit = row.split(percentage=0.85) padding = subsplit.split(percentage=0.15) colsub = padding.column() colsub = padding.column() + colsub.row().prop(ui, "menu_shadow_width") colsub.row().prop(ui, "widget_emboss") col.separator() col.separator() - col.label("Axis Colors:") + col.label("Axis & Gizmo Colors:") row = col.row() @@ -929,9 +904,13 @@ class USERPREF_PT_theme(Panel): padding = subsplit.split(percentage=0.15) colsub = padding.column() colsub = padding.column() + colsub.row().prop(ui, "gizmo_primary") + colsub.row().prop(ui, "gizmo_secondary") + colsub.row().prop(ui, "gizmo_a") + colsub.row().prop(ui, "gizmo_b") - layout.separator() - layout.separator() + col.separator() + col.separator() elif theme.theme_area == 'BONE_COLOR_SETS': col = split.column() @@ -1428,12 +1407,13 @@ class USERPREF_PT_addons(Panel): continue # check if addon should be visible with current filters - if ((filter == "All") or - (filter == info["category"]) or - (filter == "Enabled" and is_enabled) or + if ( + (filter == "All") or + (filter == info["category"]) or + (filter == "Enabled" and is_enabled) or (filter == "Disabled" and not is_enabled) or (filter == "User" and (mod.__file__.startswith((scripts_addons_folder, userpref_addons_folder)))) - ): + ): if search and search not in info["name"].lower(): if info["author"]: if search not in info["author"].lower(): @@ -1462,7 +1442,14 @@ class USERPREF_PT_addons(Panel): sub = row.row() sub.active = is_enabled sub.label(text="%s: %s" % (info["category"], info["name"])) - if info["warning"]: + + # WARNING: 2.8x exception, may be removed + # use disabled state for old add-ons, chances are they are broken. + if info.get("blender", (0,)) < (2, 80): + sub.label(text="upgrade to 2.8x required") + sub.label(icon='ERROR') + # Remove code above after 2.8x migration is complete. + elif info["warning"]: sub.label(icon='ERROR') # icon showing support level. @@ -1567,6 +1554,97 @@ class USERPREF_PT_addons(Panel): row.label(text=module_name, translate=False) +class StudioLightPanelMixin(): + bl_space_type = 'USER_PREFERENCES' + bl_region_type = 'WINDOW' + + @classmethod + def poll(cls, context): + userpref = context.user_preferences + return (userpref.active_section == 'LIGHTS') + + def _get_lights(self, userpref): + return [light for light in userpref.studio_lights if light.is_user_defined and light.orientation == self.sl_orientation] + + def draw(self, context): + layout = self.layout + userpref = context.user_preferences + lights = self._get_lights(userpref) + if lights: + flow = layout.column_flow(4) + for studio_light in lights: + self.draw_studio_light(flow, studio_light) + else: + layout.label("No custom {} configured".format(self.bl_label)) + + def draw_studio_light(self, layout, studio_light): + box = layout.box() + row = box.row() + + row.template_icon(layout.icon(studio_light), scale=6.0) + op = row.operator('wm.studiolight_uninstall', text="", icon='ZOOMOUT') + op.index = studio_light.index + + box.label(text=studio_light.name) + + +class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin): + bl_label = "MatCaps" + sl_orientation = 'MATCAP' + + +class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin): + bl_label = "World HDRI" + sl_orientation = 'WORLD' + + +class USERPREF_PT_studiolight_camera(Panel, StudioLightPanelMixin): + bl_label = "Camera HDRI" + sl_orientation = 'CAMERA' + + +class USERPREF_PT_studiolight_specular(Panel, StudioLightPanelMixin): + bl_label = "Specular Lights" + sl_orientation = 'CAMERA' + + @classmethod + def poll(cls, context): + userpref = context.user_preferences + return (userpref.active_section == 'LIGHTS') + + def opengl_light_buttons(self, column, light): + split = column.split() + + col = split.column() + col.prop(light, "use", text="Use", icon='OUTLINER_OB_LIGHT' if light.use else 'LIGHT_DATA') + + sub = col.column() + sub.active = light.use + sub.prop(light, "specular_color") + + col = split.column() + col.active = light.use + col.prop(light, "direction", text="") + + def draw(self, context): + layout = self.layout + column = layout.split() + + userpref = context.user_preferences + system = userpref.system + + light = system.solid_lights[0] + colsplit = column.split(percentage=0.85) + self.opengl_light_buttons(colsplit, light) + + light = system.solid_lights[1] + colsplit = column.split(percentage=0.85) + self.opengl_light_buttons(colsplit, light) + + light = system.solid_lights[2] + self.opengl_light_buttons(column, light) + + classes = ( USERPREF_HT_header, USERPREF_PT_tabs, @@ -1587,6 +1665,10 @@ classes = ( USERPREF_PT_input, USERPREF_MT_addons_online_resources, USERPREF_PT_addons, + USERPREF_PT_studiolight_matcaps, + USERPREF_PT_studiolight_world, + USERPREF_PT_studiolight_camera, + USERPREF_PT_studiolight_specular, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 0a365c6a20c..a26d99e9ae9 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -19,11 +19,8 @@ # <pep8 compliant> import bpy from bpy.types import Header, Menu, Panel -from .properties_grease_pencil_common import ( - GreasePencilDataPanel, - GreasePencilPaletteColorPanel, -) from .properties_paint_common import UnifiedPaintPanel +from .properties_grease_pencil_common import GreasePencilDataPanel from bpy.app.translations import contexts as i18n_contexts @@ -34,117 +31,217 @@ class VIEW3D_HT_header(Header): layout = self.layout view = context.space_data + shading = view.shading # mode_string = context.mode obj = context.active_object - toolsettings = context.tool_settings + overlay = view.overlay + tool_settings = context.tool_settings row = layout.row(align=True) row.template_header() - VIEW3D_MT_editor_menus.draw_collapsible(context, layout) + object_mode = 'OBJECT' if obj is None else obj.mode + + act_mode_item = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode] + layout.operator_menu_enum("object.mode_set", "mode", text=act_mode_item.name, icon=act_mode_item.icon) + del act_mode_item + + layout.template_header_3D_mode() - # Contains buttons like Mode, Pivot, Manipulator, Layer, Mesh Select Mode... - row = layout - layout.template_header_3D() + # Contains buttons like Mode, Pivot, Layer, Mesh Select Mode... + shading_type = view.shading.type + shading_item = bpy.types.View3DShading.bl_rna.properties["type"].enum_items[shading_type] if obj: - mode = obj.mode + # Set above: + # object_mode = obj.mode + # Particle edit - if mode == 'PARTICLE_EDIT': - row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True) + if object_mode == 'PARTICLE_EDIT': + row = layout.row() + row.prop(tool_settings.particle_edit, "select_mode", text="", expand=True) # Occlude geometry - if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or - (mode in {'WEIGHT_PAINT', 'VERTEX_PAINT'})): + if ( + (((shading.type not in {'SOLID', 'TEXTURED'}) or not shading.show_xray) and + (object_mode == 'PARTICLE_EDIT' or (object_mode == 'EDIT' and obj.type == 'MESH'))) or + (object_mode in {'WEIGHT_PAINT', 'VERTEX_PAINT'}) + ): + row = layout.row() row.prop(view, "use_occlude_geometry", text="") - # Proportional editing - if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode: + # Pose + if obj and object_mode == 'POSE': + row = layout.row(align=True) + row.operator("pose.copy", text="", icon='COPYDOWN') + row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False + row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True + + # Grease Pencil + if obj and obj.type == 'GPENCIL' and context.gpencil_data: + gpd = context.gpencil_data + + if gpd.is_stroke_paint_mode: row = layout.row(align=True) - row.prop(toolsettings, "proportional_edit", icon_only=True) - if toolsettings.proportional_edit != 'DISABLED': - row.prop(toolsettings, "proportional_edit_falloff", icon_only=True) - elif mode in {'EDIT', 'PARTICLE_EDIT'}: + row.popover( + panel="VIEW3D_PT_tools_grease_pencil_shapes", + text="Shapes" + ) + + if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode: row = layout.row(align=True) - row.prop(toolsettings, "proportional_edit", icon_only=True) - if toolsettings.proportional_edit != 'DISABLED': - row.prop(toolsettings, "proportional_edit_falloff", icon_only=True) - elif mode == 'OBJECT': + row.prop(gpd, "use_multiedit", text="", icon="FORCE_HARMONIC") + + sub = row.row(align=True) + sub.active = gpd.use_multiedit + sub.popover( + panel="VIEW3D_PT_gpencil_multi_frame", + text="Multiframe" + ) + + if gpd.use_stroke_edit_mode: row = layout.row(align=True) - row.prop(toolsettings, "use_proportional_edit_objects", icon_only=True) - if toolsettings.use_proportional_edit_objects: - row.prop(toolsettings, "proportional_edit_falloff", icon_only=True) - else: - # Proportional editing - if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode: + row.operator("gpencil.copy", text="", icon='COPYDOWN') + row.operator("gpencil.paste", text="", icon='PASTEDOWN') + row = layout.row(align=True) - row.prop(toolsettings, "proportional_edit", icon_only=True) - if toolsettings.proportional_edit != 'DISABLED': - row.prop(toolsettings, "proportional_edit_falloff", icon_only=True) + row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="") + + row.popover( + panel="VIEW3D_PT_tools_grease_pencil_interpolate", + text="Interpolate" + ) + + VIEW3D_MT_editor_menus.draw_collapsible(context, layout) + + layout.separator_spacer() + + # Mode & Transform Settings + scene = context.scene + + # Orientation + if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT'}: + orientation = scene.transform_orientation + current_orientation = scene.current_orientation + + if not current_orientation: + trans_orientation = \ + bpy.types.Scene.bl_rna.properties["transform_orientation"].enum_items[orientation] + trans_icon = getattr(trans_orientation, "icon", "BLANK1") + trans_name = getattr(trans_orientation, "name", "Orientation") + else: + trans_icon = 'VISIBLE_IPO_OFF' + trans_name = getattr(current_orientation, "name", "Orientation") + + row = layout.row(align=True) + row.popover( + panel="VIEW3D_PT_transform_orientations", + text=trans_name, + icon=trans_icon, + ) # Snap show_snap = False if obj is None: show_snap = True else: - if mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}: + if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT', + 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}: show_snap = True else: + + from .properties_paint_common import UnifiedPaintPanel paint_settings = UnifiedPaintPanel.paint_settings(context) + if paint_settings: brush = paint_settings.brush if brush and brush.stroke_method == 'CURVE': show_snap = True if show_snap: - snap_element = toolsettings.snap_element - row = layout.row(align=True) - row.prop(toolsettings, "use_snap", text="") - row.prop(toolsettings, "snap_element", icon_only=True) - if snap_element == 'INCREMENT': - row.prop(toolsettings, "use_snap_grid_absolute", text="") + snap_items = bpy.types.ToolSettings.bl_rna.properties['snap_elements'].enum_items + for elem in tool_settings.snap_elements: + # TODO: Display multiple icons. + # (Currently only one of the enabled modes icons is displayed) + icon = snap_items[elem].icon + break else: - row.prop(toolsettings, "snap_target", text="") - if obj: - if mode == 'EDIT': - row.prop(toolsettings, "use_snap_self", text="") - if mode in {'OBJECT', 'POSE', 'EDIT'} and snap_element != 'VOLUME': - row.prop(toolsettings, "use_snap_align_rotation", text="") - - if snap_element == 'VOLUME': - row.prop(toolsettings, "use_snap_peel_object", text="") - elif snap_element == 'FACE': - row.prop(toolsettings, "use_snap_project", text="") - - # AutoMerge editing + icon = 'NONE' + + row = layout.row(align=True) + row.prop(tool_settings, "use_snap", text="") + + sub = row.row(align=True) + sub.popover( + panel="VIEW3D_PT_snapping", + icon=icon, + text="", + ) + + # Proportional editing if obj: - if (mode == 'EDIT' and obj.type == 'MESH'): - layout.prop(toolsettings, "use_mesh_automerge", text="", icon='AUTOMERGE_ON') + gpd = context.gpencil_data + if gpd is not None and obj.type == 'GPENCIL': + if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode: + row = layout.row(align=True) + row.prop(tool_settings, "proportional_edit", icon_only=True) - # OpenGL render - row = layout.row(align=True) - row.operator("render.opengl", text="", icon='RENDER_STILL') - row.operator("render.opengl", text="", icon='RENDER_ANIMATION').animation = True + sub = row.row(align=True) + sub.active = tool_settings.proportional_edit != 'DISABLED' + sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True) - # Pose - if obj and mode == 'POSE': - row = layout.row(align=True) - row.operator("pose.copy", text="", icon='COPYDOWN') - row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False - row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True + elif object_mode in {'EDIT', 'PARTICLE_EDIT'}: + row = layout.row(align=True) + row.prop(tool_settings, "proportional_edit", icon_only=True) + sub = row.row(align=True) + sub.active = tool_settings.proportional_edit != 'DISABLED' + sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True) - # GPencil - if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode: + elif object_mode == 'OBJECT': + row = layout.row(align=True) + row.prop(tool_settings, "use_proportional_edit_objects", icon_only=True) + sub = row.row(align=True) + sub.active = tool_settings.use_proportional_edit_objects + sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True) + else: + if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode: + row = layout.row(align=True) + row.prop(tool_settings, "proportional_edit", icon_only=True) + sub = row.row(align=True) + sub.active = tool_settings.proportional_edit != 'DISABLED' + sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True) + + # Pivot + if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT', 'GPENCIL_SCULPT'}: + pivot_point = tool_settings.transform_pivot_point + act_pivot_point = bpy.types.ToolSettings.bl_rna.properties["transform_pivot_point"].enum_items[pivot_point] row = layout.row(align=True) - row.operator("gpencil.copy", text="", icon='COPYDOWN') - row.operator("gpencil.paste", text="", icon='PASTEDOWN') + row.popover( + panel="VIEW3D_PT_pivot_point", + icon=act_pivot_point.icon, + text="", + ) - # XXX: icon - layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH') + layout.separator_spacer() - row = layout.row(align=True) - row.prop(context.tool_settings.gpencil_sculpt, "use_select_mask") - row.prop(context.tool_settings.gpencil_sculpt, "selection_alpha", slider=True) + # Viewport Settings + layout.popover( + panel="VIEW3D_PT_object_type_visibility", + icon_value=view.icon_from_show_object_viewport, + text="", + ) + + row = layout.row(align=True) + row.prop(overlay, "show_overlays", icon='WIRE', text="") + sub = row.row(align=True) + sub.active = overlay.show_overlays + sub.popover(panel="VIEW3D_PT_overlay") + + row = layout.row(align=True) + row.prop(shading, "type", text="", expand=True) + sub = row.row(align=True) + sub.enabled = shading.type != 'RENDERED' + sub.popover(panel="VIEW3D_PT_shading") class VIEW3D_MT_editor_menus(Menu): @@ -159,13 +256,14 @@ class VIEW3D_MT_editor_menus(Menu): obj = context.active_object mode_string = context.mode edit_object = context.edit_object - gp_edit = context.gpencil_data and context.gpencil_data.use_stroke_edit_mode + gp_edit = obj and obj.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'} layout.menu("VIEW3D_MT_view") # Select Menu if gp_edit: - layout.menu("VIEW3D_MT_select_gpencil") + if mode_string not in {'GPENCIL_PAINT', 'GPENCIL_WEIGHT'}: + layout.menu("VIEW3D_MT_select_gpencil") elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}: mesh = obj.data if mesh.use_paint_mask: @@ -191,9 +289,23 @@ class VIEW3D_MT_editor_menus(Menu): layout.menu("INFO_MT_edit_armature_add", text="Add") if gp_edit: - layout.menu("VIEW3D_MT_edit_gpencil") + if obj and obj.mode == 'GPENCIL_PAINT': + layout.menu("VIEW3D_MT_paint_gpencil") + elif obj and obj.mode == 'GPENCIL_EDIT': + layout.menu("VIEW3D_MT_edit_gpencil") + elif obj and obj.mode == 'GPENCIL_SCULPT': + layout.menu("VIEW3D_MT_sculpt_gpencil") + elif obj and obj.mode == 'GPENCIL_WEIGHT': + layout.menu("VIEW3D_MT_weight_gpencil") + elif edit_object: layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower()) + + if mode_string == 'EDIT_MESH': + layout.menu("VIEW3D_MT_edit_mesh_vertices") + layout.menu("VIEW3D_MT_edit_mesh_edges") + layout.menu("VIEW3D_MT_edit_mesh_faces") + elif obj: if mode_string != 'PAINT_TEXTURE': layout.menu("VIEW3D_MT_%s" % mode_string.lower()) @@ -232,15 +344,6 @@ class VIEW3D_MT_transform_base(Menu): def draw(self, context): layout = self.layout - layout.operator("transform.translate", text="Grab/Move") - # TODO: sub-menu for grab per axis - layout.operator("transform.rotate", text="Rotate") - # TODO: sub-menu for rot per axis - layout.operator("transform.resize", text="Scale") - # TODO: sub-menu for scale per axis - - layout.separator() - layout.operator("transform.tosphere", text="To Sphere") layout.operator("transform.shear", text="Shear") layout.operator("transform.bend", text="Bend") @@ -301,6 +404,12 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base): layout.operator("object.randomize_transform") layout.operator("object.align") + # TODO: there is a strange context bug here. + """ + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator("object.transform_axis_target") + """ + # Armature EditMode extensions to Transform menu class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base): @@ -375,7 +484,7 @@ class VIEW3D_MT_snap(Menu): layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid") layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False - layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Offset)").use_offset = True + layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Keep Offset)").use_offset = True layout.operator("view3d.snap_selected_to_active", text="Selection to Active") layout.separator() @@ -416,6 +525,11 @@ class VIEW3D_MT_uv_map(Menu): layout.operator("uv.reset") + layout.separator() + + layout.operator("mesh.uvs_rotate") + layout.operator("mesh.uvs_reverse") + class VIEW3D_MT_edit_proportional(Menu): bl_label = "Proportional Editing" @@ -423,12 +537,12 @@ class VIEW3D_MT_edit_proportional(Menu): def draw(self, context): layout = self.layout - layout.props_enum(context.tool_settings, "proportional_edit") + layout.props_enum(tool_settings, "proportional_edit") layout.separator() layout.label("Falloff:") - layout.props_enum(context.tool_settings, "proportional_edit_falloff") + layout.props_enum(tool_settings, "proportional_edit_falloff") # ********** View menus ********** @@ -441,18 +555,17 @@ class VIEW3D_MT_view(Menu): layout = self.layout view = context.space_data - layout.operator("view3d.properties", icon='MENU_PANEL') layout.operator("view3d.toolshelf", icon='MENU_PANEL') + layout.operator("view3d.properties", icon='MENU_PANEL') layout.separator() - layout.operator("view3d.view_selected").use_all_regions = False + layout.operator("view3d.view_selected", text="Frame Selected").use_all_regions = False if view.region_quadviews: - layout.operator("view3d.view_selected", text="View Selected (Quad View)").use_all_regions = True + layout.operator("view3d.view_selected", text="Frame Selected (Quad View)").use_all_regions = True - layout.operator("view3d.view_all").center = False - layout.operator("view3d.localview", text="View Global/Local") - layout.operator("view3d.view_persportho") + layout.operator("view3d.view_all", text="Frame All").center = False + layout.operator("view3d.view_persportho", text="Perspective/Orthographic") layout.separator() @@ -470,18 +583,16 @@ class VIEW3D_MT_view(Menu): layout.separator() - layout.operator("view3d.layers", text="Show All Layers").nr = 0 + layout.operator("screen.animation_play", text="Play Animation") layout.separator() - layout.operator("screen.animation_play", text="Playback Animation") + layout.operator("render.opengl", icon='RENDER_STILL') + layout.operator("render.opengl", text="OpenGL Render Animation", icon='RENDER_ANIMATION').animation = True layout.separator() - layout.operator("screen.area_dupli") - layout.operator("screen.region_quadview") - layout.operator("screen.screen_full_area") - layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True + layout.menu("INFO_MT_area") class VIEW3D_MT_view_cameras(Menu): @@ -491,7 +602,7 @@ class VIEW3D_MT_view_cameras(Menu): layout = self.layout layout.operator("view3d.object_as_camera") - layout.operator("view3d.viewnumpad", text="Active Camera").type = 'CAMERA' + layout.operator("view3d.view_camera", text="Active Camera") class VIEW3D_MT_view_viewpoint(Menu): @@ -500,22 +611,22 @@ class VIEW3D_MT_view_viewpoint(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.viewnumpad", text="Camera").type = 'CAMERA' + layout.operator("view3d.view_camera", text="Camera") layout.separator() - layout.operator("view3d.viewnumpad", text="Top").type = 'TOP' - layout.operator("view3d.viewnumpad", text="Bottom").type = 'BOTTOM' + layout.operator("view3d.view_axis", text="Top").type = 'TOP' + layout.operator("view3d.view_axis", text="Bottom").type = 'BOTTOM' layout.separator() - layout.operator("view3d.viewnumpad", text="Front").type = 'FRONT' - layout.operator("view3d.viewnumpad", text="Back").type = 'BACK' + layout.operator("view3d.view_axis", text="Front").type = 'FRONT' + layout.operator("view3d.view_axis", text="Back").type = 'BACK' layout.separator() - layout.operator("view3d.viewnumpad", text="Right").type = 'RIGHT' - layout.operator("view3d.viewnumpad", text="Left").type = 'LEFT' + layout.operator("view3d.view_axis", text="Right").type = 'RIGHT' + layout.operator("view3d.view_axis", text="Left").type = 'LEFT' class VIEW3D_MT_view_navigation(Menu): @@ -562,9 +673,12 @@ class VIEW3D_MT_view_align(Menu): layout.separator() - layout.operator("view3d.view_all", text="Center Cursor and View All").center = True layout.operator("view3d.camera_to_view", text="Align Active Camera to View") layout.operator("view3d.camera_to_view_selected", text="Align Active Camera to Selected") + + layout.separator() + + layout.operator("view3d.view_all", text="Center Cursor and View All").center = True layout.operator("view3d.view_center_cursor") layout.separator() @@ -579,27 +693,31 @@ class VIEW3D_MT_view_align_selected(Menu): def draw(self, context): layout = self.layout - props = layout.operator("view3d.viewnumpad", text="Top") + props = layout.operator("view3d.view_axis", text="Top") props.align_active = True props.type = 'TOP' - props = layout.operator("view3d.viewnumpad", text="Bottom") + props = layout.operator("view3d.view_axis", text="Bottom") props.align_active = True props.type = 'BOTTOM' - props = layout.operator("view3d.viewnumpad", text="Front") + layout.separator() + + props = layout.operator("view3d.view_axis", text="Front") props.align_active = True props.type = 'FRONT' - props = layout.operator("view3d.viewnumpad", text="Back") + props = layout.operator("view3d.view_axis", text="Back") props.align_active = True props.type = 'BACK' - props = layout.operator("view3d.viewnumpad", text="Right") + layout.separator() + + props = layout.operator("view3d.view_axis", text="Right") props.align_active = True props.type = 'RIGHT' - props = layout.operator("view3d.viewnumpad", text="Left") + props = layout.operator("view3d.view_axis", text="Left") props.align_active = True props.type = 'LEFT' @@ -610,7 +728,7 @@ class VIEW3D_MT_view_borders(Menu): def draw(self, context): layout = self.layout layout.operator("view3d.clip_border", text="Clipping Border...") - layout.operator("view3d.render_border", text="Render Border...").camera_only = False + layout.operator("view3d.render_border", text="Render Border...") layout.separator() @@ -657,21 +775,21 @@ class VIEW3D_MT_select_object(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + layout.operator("object.select_all", text="All").action = 'SELECT' + layout.operator("object.select_all", text="None").action = 'DESELECT' + layout.operator("object.select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("object.select_all").action = 'TOGGLE' - layout.operator("object.select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() - layout.operator("object.select_random", text="Random") - layout.operator("object.select_mirror", text="Mirror") - layout.operator("object.select_by_layer", text="Select All by Layer") layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...") - layout.operator("object.select_camera", text="Select Camera") + layout.operator("object.select_camera", text="Select Active Camera") + layout.operator("object.select_mirror", text="Mirror Selection") + layout.operator("object.select_random", text="Select Random") layout.separator() @@ -679,8 +797,8 @@ class VIEW3D_MT_select_object(Menu): layout.separator() - layout.operator_menu_enum("object.select_grouped", "type", text="Grouped") - layout.operator_menu_enum("object.select_linked", "type", text="Linked") + layout.operator_menu_enum("object.select_grouped", "type", text="Select Grouped") + layout.operator_menu_enum("object.select_linked", "type", text="Select Linked") layout.operator("object.select_pattern", text="Select Pattern...") @@ -717,13 +835,17 @@ class VIEW3D_MT_select_pose(Menu): def draw(self, context): layout = self.layout + layout.operator("pose.select_all", text="All").action = 'SELECT' + layout.operator("pose.select_all", text="None").action = 'DESELECT' + layout.operator("pose.select_all", text="Invert").action = 'INVERT' + + layout.separator() + layout.operator("view3d.select_border") layout.operator("view3d.select_circle") layout.separator() - layout.operator("pose.select_all").action = 'TOGGLE' - layout.operator("pose.select_all", text="Inverse").action = 'INVERT' layout.operator("pose.select_mirror", text="Flip Active") layout.separator() @@ -747,14 +869,18 @@ class VIEW3D_MT_select_particle(Menu): def draw(self, context): layout = self.layout + layout.operator("particle.select_all", text="All").action = 'SELECT' + layout.operator("particle.select_all", text="None").action = 'DESELECT' + layout.operator("particle.select_all", text="Invert").action = 'INVERT' + + layout.separator() + layout.operator("view3d.select_border") layout.operator("view3d.select_circle") layout.separator() - layout.operator("particle.select_all").action = 'TOGGLE' layout.operator("particle.select_linked") - layout.operator("particle.select_all", text="Inverse").action = 'INVERT' layout.separator() @@ -789,7 +915,8 @@ class VIEW3D_MT_edit_mesh_select_by_trait(Menu): def draw(self, context): layout = self.layout - if context.scene.tool_settings.mesh_select_mode[2] is False: + tool_settings = context.tool_settings + if tool_settings.mesh_select_mode[2] is False: layout.operator("mesh.select_non_manifold", text="Non Manifold") layout.operator("mesh.select_loose", text="Loose Geometry") layout.operator("mesh.select_interior_faces", text="Interior Faces") @@ -847,25 +974,26 @@ class VIEW3D_MT_select_edit_mesh(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + # primitive + layout.operator("mesh.select_all", text="All").action = 'SELECT' + layout.operator("mesh.select_all", text="None").action = 'DESELECT' + layout.operator("mesh.select_all", text="Invert").action = 'INVERT' layout.separator() - # primitive - layout.operator("mesh.select_all").action = 'TOGGLE' - layout.operator("mesh.select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() # numeric - layout.operator("mesh.select_random", text="Random") + layout.operator("mesh.select_random", text="Select Random") layout.operator("mesh.select_nth") layout.separator() # geometric - layout.operator("mesh.edges_select_sharp", text="Sharp Edges") + layout.operator("mesh.edges_select_sharp", text="Select Sharp Edges") layout.separator() @@ -891,7 +1019,7 @@ class VIEW3D_MT_select_edit_mesh(Menu): layout.separator() layout.operator("mesh.select_axis", text="Side of Active") - layout.operator("mesh.select_mirror", text="Mirror") + layout.operator("mesh.select_mirror", text="Mirror Selection") class VIEW3D_MT_select_edit_curve(Menu): @@ -900,13 +1028,14 @@ class VIEW3D_MT_select_edit_curve(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + layout.operator("curve.select_all", text="All").action = 'SELECT' + layout.operator("curve.select_all", text="None").action = 'DESELECT' + layout.operator("curve.select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("curve.select_all").action = 'TOGGLE' - layout.operator("curve.select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() @@ -934,13 +1063,14 @@ class VIEW3D_MT_select_edit_surface(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + layout.operator("curve.select_all", text="All").action = 'SELECT' + layout.operator("curve.select_all", text="None").action = 'DESELECT' + layout.operator("curve.select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("curve.select_all").action = 'TOGGLE' - layout.operator("curve.select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() @@ -967,10 +1097,6 @@ class VIEW3D_MT_select_edit_text(Menu): def draw(self, context): layout = self.layout - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - layout.operator("font.text_paste", text="Paste") layout.operator("font.text_cut", text="Cut") layout.operator("font.text_copy", text="Copy") @@ -990,13 +1116,14 @@ class VIEW3D_MT_select_edit_metaball(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + layout.operator("mball.select_all", text="All").action = 'SELECT' + layout.operator("mball.select_all", text="None").action = 'DESELECT' + layout.operator("mball.select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("mball.select_all").action = 'TOGGLE' - layout.operator("mball.select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() @@ -1013,13 +1140,14 @@ class VIEW3D_MT_select_edit_lattice(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + layout.operator("lattice.select_all", text="All").action = 'SELECT' + layout.operator("lattice.select_all", text="None").action = 'DESELECT' + layout.operator("lattice.select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("lattice.select_all").action = 'TOGGLE' - layout.operator("lattice.select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() @@ -1037,13 +1165,17 @@ class VIEW3D_MT_select_edit_armature(Menu): def draw(self, context): layout = self.layout + layout.operator("armature.select_all", text="All").action = 'SELECT' + layout.operator("armature.select_all", text="None").action = 'DESELECT' + layout.operator("armature.select_all", text="Invert").action = 'INVERT' + + layout.separator() + layout.operator("view3d.select_border") layout.operator("view3d.select_circle") layout.separator() - layout.operator("armature.select_all").action = 'TOGGLE' - layout.operator("armature.select_all", text="Inverse").action = 'INVERT' layout.operator("armature.select_mirror", text="Mirror").extend = False layout.separator() @@ -1081,17 +1213,19 @@ class VIEW3D_MT_select_gpencil(Menu): def draw(self, context): layout = self.layout - layout.operator("gpencil.select_border") - layout.operator("gpencil.select_circle") + layout.operator("gpencil.select_all", text="All").action = 'SELECT' + layout.operator("gpencil.select_all", text="None").action = 'DESELECT' + layout.operator("gpencil.select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("gpencil.select_all", text="(De)select All").action = 'TOGGLE' - layout.operator("gpencil.select_all", text="Inverse").action = 'INVERT' + layout.operator("gpencil.select_border") + layout.operator("gpencil.select_circle") layout.separator() layout.operator("gpencil.select_linked", text="Linked") + layout.operator("gpencil.select_alternate") layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped") layout.separator() @@ -1111,13 +1245,14 @@ class VIEW3D_MT_select_paint_mask(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + layout.operator("paint.face_select_all", text="All").action = 'SELECT' + layout.operator("paint.face_select_all", text="None").action = 'DESELECT' + layout.operator("paint.face_select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("paint.face_select_all").action = 'TOGGLE' - layout.operator("paint.face_select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() @@ -1130,13 +1265,14 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu): def draw(self, context): layout = self.layout - layout.operator("view3d.select_border") - layout.operator("view3d.select_circle") + layout.operator("paint.vert_select_all", text="All").action = 'SELECT' + layout.operator("paint.vert_select_all", text="None").action = 'DESELECT' + layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT' layout.separator() - layout.operator("paint.vert_select_all").action = 'TOGGLE' - layout.operator("paint.vert_select_all", text="Inverse").action = 'INVERT' + layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() @@ -1183,13 +1319,23 @@ class INFO_MT_mesh_add(Menu): bl_label = "Mesh" def draw(self, context): - from .space_view3d_toolbar import VIEW3D_PT_tools_add_object - layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - VIEW3D_PT_tools_add_object.draw_add_mesh(layout) + layout.operator("mesh.primitive_plane_add", text="Plane", icon='MESH_PLANE') + layout.operator("mesh.primitive_cube_add", text="Cube", icon='MESH_CUBE') + layout.operator("mesh.primitive_circle_add", text="Circle", icon='MESH_CIRCLE') + layout.operator("mesh.primitive_uv_sphere_add", text="UV Sphere", icon='MESH_UVSPHERE') + layout.operator("mesh.primitive_ico_sphere_add", text="Ico Sphere", icon='MESH_ICOSPHERE') + layout.operator("mesh.primitive_cylinder_add", text="Cylinder", icon='MESH_CYLINDER') + layout.operator("mesh.primitive_cone_add", text="Cone", icon='MESH_CONE') + layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS') + + layout.separator() + + layout.operator("mesh.primitive_grid_add", text="Grid", icon='MESH_GRID') + layout.operator("mesh.primitive_monkey_add", text="Monkey", icon='MESH_MONKEY') class INFO_MT_curve_add(Menu): @@ -1197,12 +1343,22 @@ class INFO_MT_curve_add(Menu): bl_label = "Curve" def draw(self, context): - from .space_view3d_toolbar import VIEW3D_PT_tools_add_object layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - VIEW3D_PT_tools_add_object.draw_add_curve(layout) + layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE') + layout.operator("curve.primitive_bezier_circle_add", text="Circle", icon='CURVE_BEZCIRCLE') + + layout.separator() + + layout.operator("curve.primitive_nurbs_curve_add", text="Nurbs Curve", icon='CURVE_NCURVE') + layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE') + layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH') + + layout.separator() + + layout.operator("curve.draw", icon='LINE_DATA') class INFO_MT_surface_add(Menu): @@ -1210,12 +1366,17 @@ class INFO_MT_surface_add(Menu): bl_label = "Surface" def draw(self, context): - from .space_view3d_toolbar import VIEW3D_PT_tools_add_object layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - VIEW3D_PT_tools_add_object.draw_add_surface(layout) + layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE') + layout.operator("surface.primitive_nurbs_surface_circle_add", text="Nurbs Circle", icon='SURFACE_NCIRCLE') + layout.operator("surface.primitive_nurbs_surface_surface_add", text="Nurbs Surface", icon='SURFACE_NSURFACE') + layout.operator("surface.primitive_nurbs_surface_cylinder_add", + text="Nurbs Cylinder", icon='SURFACE_NCYLINDER') + layout.operator("surface.primitive_nurbs_surface_sphere_add", text="Nurbs Sphere", icon='SURFACE_NSPHERE') + layout.operator("surface.primitive_nurbs_surface_torus_add", text="Nurbs Torus", icon='SURFACE_NTORUS') class INFO_MT_metaball_add(Menu): @@ -1267,15 +1428,26 @@ class INFO_MT_armature_add(Menu): layout.operator("object.armature_add", text="Single Bone", icon='BONE_DATA') -class INFO_MT_lamp_add(Menu): - bl_idname = "INFO_MT_lamp_add" - bl_label = "Lamp" +class INFO_MT_light_add(Menu): + bl_idname = "INFO_MT_light_add" + bl_label = "Light" + + def draw(self, context): + layout = self.layout + + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator_enum("object.light_add", "type") + + +class INFO_MT_lightprobe_add(Menu): + bl_idname = "INFO_MT_lightprobe_add" + bl_label = "Light Probe" def draw(self, context): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator_enum("object.lamp_add", "type") + layout.operator_enum("object.lightprobe_add", "type") class INFO_MT_camera_add(Menu): @@ -1309,6 +1481,7 @@ class INFO_MT_add(Menu): layout.menu("INFO_MT_surface_add", icon='OUTLINER_OB_SURFACE') layout.menu("INFO_MT_metaball_add", text="Metaball", icon='OUTLINER_OB_META') layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT') + layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL') layout.separator() layout.menu("INFO_MT_armature_add", icon='OUTLINER_OB_ARMATURE') @@ -1324,39 +1497,34 @@ class INFO_MT_add(Menu): else: INFO_MT_camera_add.draw(self, context) - layout.menu("INFO_MT_lamp_add", icon='OUTLINER_OB_LAMP') + layout.menu("INFO_MT_light_add", icon='OUTLINER_OB_LIGHT') + layout.separator() + layout.menu("INFO_MT_lightprobe_add", icon='OUTLINER_OB_LIGHTPROBE') layout.separator() layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_FORCE_FIELD') layout.separator() - if len(bpy.data.groups) > 10: - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("object.group_instance_add", text="Group Instance...", icon='OUTLINER_OB_GROUP_INSTANCE') + has_collections = bool(bpy.data.collections) + col = layout.column() + col.enabled = has_collections + + if not has_collections or len(bpy.data.collections) > 10: + col.operator_context = 'INVOKE_REGION_WIN' + col.operator( + "object.collection_instance_add", + text="Collection Instance..." if has_collections else "No Collections to Instance", + icon='OUTLINER_OB_GROUP_INSTANCE', + ) else: - layout.operator_menu_enum( - "object.group_instance_add", - "group", - text="Group Instance", + col.operator_menu_enum( + "object.collection_instance_add", + "collection", + text="Collection Instance", icon='OUTLINER_OB_GROUP_INSTANCE', ) -class VIEW3D_MT_undo_redo(Menu): - bl_label = "Undo/Redo" - _operator_name = "" - - def draw(self, context): - layout = self.layout - - layout.operator("ed.undo") - layout.operator("ed.redo") - - layout.separator() - - layout.operator("ed.undo_history") - - class VIEW3D_MT_object_relations(Menu): bl_label = "Relations" @@ -1384,26 +1552,11 @@ class VIEW3D_MT_object(Menu): def draw(self, context): layout = self.layout - view = context.space_data - is_local_view = (view.local_view is not None) - - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - - layout.operator("object.delete", text="Delete...").use_global = False - - layout.separator() layout.menu("VIEW3D_MT_transform_object") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_object_clear") layout.menu("VIEW3D_MT_object_apply") - - layout.separator() - - layout.menu("VIEW3D_MT_object_parent") - layout.menu("VIEW3D_MT_object_group") layout.menu("VIEW3D_MT_snap") layout.separator() @@ -1411,22 +1564,30 @@ class VIEW3D_MT_object(Menu): layout.operator("object.duplicate_move") layout.operator("object.duplicate_move_linked") layout.operator("object.join") - if is_local_view: - layout.operator_context = 'EXEC_REGION_WIN' - layout.operator("object.move_to_layer", text="Move out of Local View") - layout.operator_context = 'INVOKE_REGION_WIN' - else: - layout.operator("object.move_to_layer", text="Move to Layer...") layout.separator() - layout.menu("VIEW3D_MT_make_links", text="Make Links...") + + layout.operator("view3d.copybuffer", text="Copy Objects") + layout.operator("view3d.pastebuffer", text="Paste Objects") + + layout.separator() + + layout.menu("VIEW3D_MT_object_parent") + layout.menu("VIEW3D_MT_object_collection") layout.menu("VIEW3D_MT_object_relations") layout.menu("VIEW3D_MT_object_constraints") layout.menu("VIEW3D_MT_object_track") + layout.menu("VIEW3D_MT_make_links", text="Make Links...") + + layout.separator() + + layout.operator("object.shade_smooth") + layout.operator("object.shade_flat") layout.separator() layout.menu("VIEW3D_MT_object_animation") + layout.menu("VIEW3D_MT_object_rigid_body") layout.separator() @@ -1434,13 +1595,15 @@ class VIEW3D_MT_object(Menu): layout.separator() - layout.menu("VIEW3D_MT_object_game") + layout.operator_menu_enum("object.convert", "target") layout.separator() layout.menu("VIEW3D_MT_object_showhide") - layout.operator_menu_enum("object.convert", "target") + layout.separator() + + layout.operator("object.delete", text="Delete...").use_global = False class VIEW3D_MT_object_animation(Menu): @@ -1459,6 +1622,32 @@ class VIEW3D_MT_object_animation(Menu): layout.operator("nla.bake", text="Bake Action...") +class VIEW3D_MT_object_rigid_body(Menu): + bl_label = "Rigid Body" + + def draw(self, context): + layout = self.layout + + layout.operator("rigidbody.objects_add", text="Add Active").type = 'ACTIVE' + layout.operator("rigidbody.objects_add", text="Add Passive").type = 'PASSIVE' + + layout.separator() + + layout.operator("rigidbody.objects_remove", text="Remove") + + layout.separator() + + layout.operator("rigidbody.shape_change", text="Change Shape") + layout.operator("rigidbody.mass_calculate", text="Calculate Mass") + layout.operator("rigidbody.object_settings_copy", text="Copy from Active") + layout.operator("object.visual_transform_apply", text="Apply Transformation") + layout.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes") + + layout.separator() + + layout.operator("rigidbody.connect", text="Connect") + + class VIEW3D_MT_object_clear(Menu): bl_label = "Clear" @@ -1475,7 +1664,7 @@ class VIEW3D_MT_object_clear(Menu): class VIEW3D_MT_object_specials(Menu): - bl_label = "Specials" + bl_label = "Object Context Menu" @classmethod def poll(cls, context): @@ -1488,6 +1677,42 @@ class VIEW3D_MT_object_specials(Menu): scene = context.scene obj = context.object + layout.operator("view3d.copybuffer", text="Copy Objects", icon='COPYDOWN') + layout.operator("view3d.pastebuffer", text="Paste Objects", icon='PASTEDOWN') + + layout.separator() + + layout.operator("object.duplicate_move") + layout.operator("object.duplicate_move_linked") + + layout.separator() + + layout.menu("VIEW3D_MT_snap") + layout.menu("VIEW3D_MT_object_parent") + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator("object.move_to_collection") + + layout.separator() + + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...") + + layout.separator() + + layout.operator("object.delete", text="Delete...").use_global = False + + if obj.type == 'MESH': + + layout.separator() + + layout.operator("object.shade_smooth", text="Smooth Shading") + layout.operator("object.shade_flat", text="Flat Shading") + + layout.separator() + + layout.operator("object.origin_set") + layout.operator("object.join") + layout.operator_menu_enum("object.convert", "target") + if obj.type == 'CAMERA': layout.operator_context = 'INVOKE_REGION_WIN' @@ -1544,59 +1769,46 @@ class VIEW3D_MT_object_specials(Menu): props.input_scale = 0.01 props.header_text = "Empty Draw Size: %.3f" - if obj.type == 'LAMP': - lamp = obj.data + if obj.type == 'LIGHT': + light = obj.data layout.operator_context = 'INVOKE_REGION_WIN' - if scene.render.use_shading_nodes: - emission_node = None - if lamp.node_tree: - for node in lamp.node_tree.nodes: - if getattr(node, "type", None) == 'EMISSION': - emission_node = node - break - - if emission_node is not None: - props = layout.operator("wm.context_modal_mouse", text="Strength") - props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.node_tree" \ - ".nodes[\"" + emission_node.name + "\"]" \ - ".inputs[\"Strength\"].default_value" - props.header_text = "Lamp Strength: %.3f" - props.input_scale = 0.1 - - if lamp.type == 'AREA': - props = layout.operator("wm.context_modal_mouse", text="Size X") - props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.size" - props.header_text = "Lamp Size X: %.3f" + emission_node = None + if light.node_tree: + for node in light.node_tree.nodes: + if getattr(node, "type", None) == 'EMISSION': + emission_node = node + break - if lamp.shape == 'RECTANGLE': - props = layout.operator("wm.context_modal_mouse", text="Size Y") - props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.size_y" - props.header_text = "Lamp Size Y: %.3f" + if emission_node is not None: + props = layout.operator("wm.context_modal_mouse", text="Strength") + props.data_path_iter = "selected_editable_objects" + props.data_path_item = "data.node_tree" \ + ".nodes[\"" + emission_node.name + "\"]" \ + ".inputs[\"Strength\"].default_value" + props.header_text = "Light Strength: %.3f" + props.input_scale = 0.1 - elif lamp.type in {'SPOT', 'POINT', 'SUN'}: - props = layout.operator("wm.context_modal_mouse", text="Size") - props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.shadow_soft_size" - props.header_text = "Lamp Size: %.3f" - else: - props = layout.operator("wm.context_modal_mouse", text="Energy") + if light.type == 'AREA': + props = layout.operator("wm.context_modal_mouse", text="Size X") props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.energy" - props.header_text = "Lamp Energy: %.3f" + props.data_path_item = "data.size" + props.header_text = "Light Size X: %.3f" - if lamp.type in {'SPOT', 'AREA', 'POINT'}: - props = layout.operator("wm.context_modal_mouse", text="Falloff Distance") + if light.shape in {'RECTANGLE', 'ELLIPSE'}: + props = layout.operator("wm.context_modal_mouse", text="Size Y") props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.distance" - props.input_scale = 0.1 - props.header_text = "Lamp Falloff Distance: %.1f" + props.data_path_item = "data.size_y" + props.header_text = "Light Size Y: %.3f" - if lamp.type == 'SPOT': + elif light.type in {'SPOT', 'POINT', 'SUN'}: + props = layout.operator("wm.context_modal_mouse", text="Size") + props.data_path_iter = "selected_editable_objects" + props.data_path_item = "data.shadow_soft_size" + props.header_text = "Light Size: %.3f" + + if light.type == 'SPOT': layout.separator() props = layout.operator("wm.context_modal_mouse", text="Spot Size") props.data_path_iter = "selected_editable_objects" @@ -1610,23 +1822,15 @@ class VIEW3D_MT_object_specials(Menu): props.input_scale = -0.01 props.header_text = "Spot Blend: %.2f" - if not scene.render.use_shading_nodes: - props = layout.operator("wm.context_modal_mouse", text="Clip Start") - props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.shadow_buffer_clip_start" - props.input_scale = 0.05 - props.header_text = "Clip Start: %.2f" - - props = layout.operator("wm.context_modal_mouse", text="Clip End") - props.data_path_iter = "selected_editable_objects" - props.data_path_item = "data.shadow_buffer_clip_end" - props.input_scale = 0.05 - props.header_text = "Clip End: %.2f" - layout.separator() +class VIEW3D_MT_object_shading(Menu): + # XXX, this menu is a place to store shading operator in object mode + bl_label = "Shading" - props = layout.operator("object.isolate_type_render") - props = layout.operator("object.hide_render_clear_all") + def draw(self, context): + layout = self.layout + layout.operator("object.shade_smooth", text="Smooth") + layout.operator("object.shade_flat", text="Flat") class VIEW3D_MT_object_apply(Menu): @@ -1712,21 +1916,21 @@ class VIEW3D_MT_object_track(Menu): layout.operator_enum("object.track_clear", "type") -class VIEW3D_MT_object_group(Menu): - bl_label = "Group" +class VIEW3D_MT_object_collection(Menu): + bl_label = "Collection" def draw(self, context): layout = self.layout - layout.operator("group.create") - # layout.operator_menu_enum("group.objects_remove", "group") # BUGGY - layout.operator("group.objects_remove") - layout.operator("group.objects_remove_all") + layout.operator("collection.create") + # layout.operator_menu_enum("collection.objects_remove", "collection") # BUGGY + layout.operator("collection.objects_remove") + layout.operator("collection.objects_remove_all") layout.separator() - layout.operator("group.objects_add_active") - layout.operator("group.objects_remove_active") + layout.operator("collection.objects_add_active") + layout.operator("collection.objects_remove_active") class VIEW3D_MT_object_constraints(Menu): @@ -1777,23 +1981,23 @@ class VIEW3D_MT_make_single_user(Menu): props = layout.operator("object.make_single_user", text="Object") props.object = True - props.obdata = props.material = props.texture = props.animation = False + props.obdata = props.material = props.animation = False props = layout.operator("object.make_single_user", text="Object & Data") props.object = props.obdata = True - props.material = props.texture = props.animation = False + props.material = props.animation = False - props = layout.operator("object.make_single_user", text="Object & Data & Materials+Tex") - props.object = props.obdata = props.material = props.texture = True + props = layout.operator("object.make_single_user", text="Object & Data & Materials") + props.object = props.obdata = props.material = True props.animation = False - props = layout.operator("object.make_single_user", text="Materials+Tex") - props.material = props.texture = True + props = layout.operator("object.make_single_user", text="Materials") + props.material = True props.object = props.obdata = props.animation = False props = layout.operator("object.make_single_user", text="Object Animation") props.animation = True - props.object = props.obdata = props.material = props.texture = False + props.object = props.obdata = props.material = False class VIEW3D_MT_make_links(Menu): @@ -1819,36 +2023,17 @@ class VIEW3D_MT_make_links(Menu): layout.operator("object.join_uvs") # stupid place to add this! -class VIEW3D_MT_object_game(Menu): - bl_label = "Game" - - def draw(self, context): - layout = self.layout - - layout.operator("object.logic_bricks_copy", text="Copy Logic Bricks") - layout.operator("object.game_physics_copy", text="Copy Physics Properties") - - layout.separator() - - layout.operator("object.game_property_copy", text="Replace Properties").operation = 'REPLACE' - layout.operator("object.game_property_copy", text="Merge Properties").operation = 'MERGE' - layout.operator_menu_enum("object.game_property_copy", "property", text="Copy Properties...") - - layout.separator() - - layout.operator("object.game_property_clear") - - class VIEW3D_MT_brush(Menu): bl_label = "Brush" def draw(self, context): layout = self.layout + tool_settings = context.tool_settings settings = UnifiedPaintPanel.paint_settings(context) brush = getattr(settings, "brush", None) - ups = context.tool_settings.unified_paint_settings + ups = tool_settings.unified_paint_settings layout.prop(ups, "use_unified_size", text="Unified Size") layout.prop(ups, "use_unified_strength", text="Unified Strength") if context.image_paint_object or context.vertex_paint_object: @@ -1915,10 +2100,6 @@ class VIEW3D_MT_paint_vertex(Menu): def draw(self, context): layout = self.layout - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - layout.operator("paint.vertex_color_set") layout.operator("paint.vertex_color_smooth") layout.operator("paint.vertex_color_dirt") @@ -1987,17 +2168,15 @@ class VIEW3D_MT_vertex_group(Menu): class VIEW3D_MT_paint_weight(Menu): bl_label = "Weights" - def draw(self, context): - layout = self.layout - - layout.menu("VIEW3D_MT_undo_redo") + @staticmethod + def draw_generic(layout, is_editmode=False): - layout.separator() + if not is_editmode: - layout.operator("paint.weight_from_bones", text="Assign Automatic From Bones").type = 'AUTOMATIC' - layout.operator("paint.weight_from_bones", text="Assign From Bone Envelopes").type = 'ENVELOPES' + layout.operator("paint.weight_from_bones", text="Assign Automatic From Bones").type = 'AUTOMATIC' + layout.operator("paint.weight_from_bones", text="Assign From Bone Envelopes").type = 'ENVELOPES' - layout.separator() + layout.separator() layout.operator("object.vertex_group_normalize_all", text="Normalize All") layout.operator("object.vertex_group_normalize", text="Normalize") @@ -2014,16 +2193,21 @@ class VIEW3D_MT_paint_weight(Menu): layout.operator("object.vertex_group_levels", text="Levels") layout.operator("object.vertex_group_smooth", text="Smooth") - props = layout.operator("object.data_transfer", text="Transfer Weights") - props.use_reverse_transfer = True - props.data_type = 'VGROUP_WEIGHTS' + if not is_editmode: + props = layout.operator("object.data_transfer", text="Transfer Weights") + props.use_reverse_transfer = True + props.data_type = 'VGROUP_WEIGHTS' layout.operator("object.vertex_group_limit_total", text="Limit Total") layout.operator("object.vertex_group_fix", text="Fix Deforms") - layout.separator() + if not is_editmode: + layout.separator() - layout.operator("paint.weight_set") + layout.operator("paint.weight_set") + + def draw(self, context): + self.draw_generic(self.layout, is_editmode=False) class VIEW3D_MT_sculpt(Menu): @@ -2032,12 +2216,8 @@ class VIEW3D_MT_sculpt(Menu): def draw(self, context): layout = self.layout - toolsettings = context.tool_settings - sculpt = toolsettings.sculpt - - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() + tool_settings = context.tool_settings + sculpt = tool_settings.sculpt layout.prop(sculpt, "use_symmetry_x") layout.prop(sculpt, "use_symmetry_y") @@ -2103,16 +2283,9 @@ class VIEW3D_MT_particle(Menu): def draw(self, context): layout = self.layout + tool_settings = context.tool_settings - particle_edit = context.tool_settings.particle_edit - - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - - layout.operator("particle.delete") - - layout.separator() + particle_edit = tool_settings.particle_edit layout.operator("particle.mirror") @@ -2131,14 +2304,19 @@ class VIEW3D_MT_particle(Menu): layout.menu("VIEW3D_MT_particle_showhide") + layout.separator() + + layout.operator("particle.delete") + class VIEW3D_MT_particle_specials(Menu): - bl_label = "Specials" + bl_label = "Particle Context Menu" def draw(self, context): layout = self.layout + tool_settings = context.tool_settings - particle_edit = context.tool_settings.particle_edit + particle_edit = tool_settings.particle_edit layout.operator("particle.rekey") @@ -2162,6 +2340,13 @@ class VIEW3D_MT_particle_specials(Menu): if particle_edit.select_mode == 'POINT': layout.separator() + + layout.operator("particle.select_all", text="All").action = 'SELECT' + layout.operator("particle.select_all", text="None").action = 'DESELECT' + layout.operator("particle.select_all", text="Invert").action = 'INVERT' + + layout.separator() + layout.operator("particle.select_roots") layout.operator("particle.select_tips") @@ -2176,9 +2361,7 @@ class VIEW3D_MT_particle_specials(Menu): layout.separator() - layout.operator("particle.select_all").action = 'TOGGLE' layout.operator("particle.select_linked") - layout.operator("particle.select_all", text="Inverse").action = 'INVERT' class VIEW3D_MT_particle_showhide(ShowHideMenu, Menu): @@ -2191,10 +2374,6 @@ class VIEW3D_MT_pose(Menu): def draw(self, context): layout = self.layout - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - layout.menu("VIEW3D_MT_transform_armature") layout.menu("VIEW3D_MT_pose_transform") @@ -2387,30 +2566,41 @@ class VIEW3D_MT_pose_apply(Menu): class VIEW3D_MT_pose_specials(Menu): - bl_label = "Specials" + bl_label = "Pose Context Menu" def draw(self, context): layout = self.layout - layout.operator("paint.weight_from_bones", text="Assign Automatic from Bones").type = 'AUTOMATIC' - layout.operator("paint.weight_from_bones", text="Assign from Bone Envelopes").type = 'ENVELOPES' + layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...") + + layout.separator() + + layout.operator("pose.copy") + layout.operator("pose.paste").flipped = False + layout.operator("pose.paste", text="Paste X-Flipped Pose").flipped = True layout.separator() layout.operator("pose.select_constraint_target") - layout.operator("pose.flip_names") + + layout.separator() + + layout.operator("pose.paths_calculate", text="Calculate") + layout.operator("pose.paths_clear", text="Clear") layout.separator() layout.operator("pose.paths_calculate") layout.operator("pose.paths_clear") - layout.operator("pose.user_transforms_clear") - layout.operator("pose.user_transforms_clear", text="Clear User Transforms (All)").only_selected = False - layout.operator("pose.relax") layout.separator() - layout.operator_menu_enum("pose.autoside_names", "axis") + layout.operator("pose.hide").unselected = False + layout.operator("pose.reveal") + + layout.separator() + + layout.operator("pose.user_transforms_clear") class BoneOptions: @@ -2466,16 +2656,9 @@ class VIEW3D_MT_edit_mesh(Menu): def draw(self, context): layout = self.layout + tool_settings = context.tool_settings - toolsettings = context.tool_settings - - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - - layout.menu("VIEW3D_MT_edit_mesh_delete") - - layout.separator() + with_bullet = bpy.app.build_options.bullet layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_mirror") @@ -2487,85 +2670,127 @@ class VIEW3D_MT_edit_mesh(Menu): layout.separator() - layout.operator("mesh.duplicate_move") + layout.operator("mesh.duplicate_move", text="Duplicate") layout.menu("VIEW3D_MT_edit_mesh_extrude") + layout.operator("mesh.split") + layout.operator("mesh.bisect") - layout.separator() - - layout.menu("VIEW3D_MT_edit_mesh_vertices") - layout.menu("VIEW3D_MT_edit_mesh_edges") - layout.menu("VIEW3D_MT_edit_mesh_faces") + if with_bullet: + layout.operator("mesh.convex_hull") layout.separator() - layout.menu("VIEW3D_MT_edit_mesh_normals") - layout.menu("VIEW3D_MT_edit_mesh_clean") + layout.operator("mesh.symmetrize") + layout.operator("mesh.symmetry_snap") layout.separator() - layout.operator("mesh.symmetrize") - layout.operator("mesh.symmetry_snap") - layout.operator("mesh.bisect") + layout.menu("VIEW3D_MT_edit_mesh_normals") + layout.menu("VIEW3D_MT_edit_mesh_shading") + layout.menu("VIEW3D_MT_edit_mesh_weights") layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...") layout.separator() - layout.prop(toolsettings, "use_mesh_automerge") - layout.menu("VIEW3D_MT_edit_proportional") + layout.menu("VIEW3D_MT_edit_mesh_showhide") + layout.operator_menu_enum("mesh.separate", "type") + layout.menu("VIEW3D_MT_edit_mesh_clean") layout.separator() - layout.menu("VIEW3D_MT_edit_mesh_showhide") + layout.menu("VIEW3D_MT_edit_mesh_delete") class VIEW3D_MT_edit_mesh_specials(Menu): - bl_label = "Specials" + bl_label = "Mesh Context Menu" def draw(self, context): layout = self.layout + select_mode = context.tool_settings.mesh_select_mode + layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.subdivide", text="Subdivide").smoothness = 0.0 - layout.operator("mesh.subdivide", text="Subdivide Smooth").smoothness = 1.0 + layout.operator("mesh.subdivide", text="Subdivide") layout.separator() - layout.operator("mesh.merge", text="Merge...") - layout.operator("mesh.remove_doubles") + layout.operator("mesh.duplicate_move", text="Duplicate") - layout.separator() + # Vertex Select Commands + if select_mode[0]: + layout.separator() - layout.operator("mesh.hide", text="Hide").unselected = False - layout.operator("mesh.reveal", text="Reveal") - layout.operator("mesh.select_all", text="Select Inverse").action = 'INVERT' + layout.operator("mesh.edge_face_add", text="New Edge/Face from Vertices") + layout.operator("mesh.vert_connect_path", text="Connect Vertex Path") + layout.operator("mesh.vert_connect", text="Connect Vertex Pairs") - layout.separator() + layout.separator() - layout.operator("mesh.flip_normals") - layout.operator("mesh.vertices_smooth", text="Smooth") - layout.operator("mesh.vertices_smooth_laplacian", text="Laplacian Smooth") + layout.operator("mesh.vertices_smooth", text="Smooth") + layout.operator("mesh.vertices_smooth_laplacian", text="Smooth Laplacian") - layout.separator() + layout.separator() + layout.operator("mesh.merge", text="Merge Vertices...") + layout.operator("mesh.remove_doubles", text="Remove Double Vertices") + layout.operator("mesh.dissolve_verts") + layout.operator("mesh.delete", text="Delete Vertices").type = 'VERT' - layout.operator("mesh.inset") - layout.operator("mesh.bevel", text="Bevel") - layout.operator("mesh.bridge_edge_loops") + # Edge Select Commands + if select_mode[1]: + layout.separator() - layout.separator() + layout.operator("mesh.bridge_edge_loops", text="Bridge Edge Loops") - layout.operator("mesh.faces_shade_smooth") - layout.operator("mesh.faces_shade_flat") + layout.separator() + + layout.operator("mesh.dissolve_edges") + layout.operator("mesh.delete", text="Delete Edges").type = 'EDGE' + + # Face Select Commands + if select_mode[2]: + layout.separator() + + layout.operator("mesh.faces_shade_smooth") + layout.operator("mesh.faces_shade_flat") + + layout.separator() + + layout.operator("mesh.bridge_edge_loops", text="Bridge Faces") + + layout.separator() + + layout.operator("mesh.poke") + + layout.separator() + + props = layout.operator("mesh.quads_convert_to_tris") + props.quad_method = props.ngon_method = 'BEAUTY' + layout.operator("mesh.tris_convert_to_quads") + + layout.separator() + + layout.menu("VIEW3D_MT_uv_map", text="UV Unwrap Faces...") + + layout.separator() + + layout.operator("mesh.dissolve_faces") + layout.operator("mesh.delete", text="Delete Faces").type = 'FACE' + + # General Mesh Commands layout.separator() - layout.operator("mesh.blend_from_shape") - layout.operator("mesh.shape_propagate_to_all") - layout.operator("mesh.shortest_path_select") - layout.operator("mesh.sort_elements") + layout.menu("VIEW3D_MT_snap", text="Snap...") + layout.operator("transform.mirror", text="Mirror") layout.operator("mesh.symmetrize") layout.operator("mesh.symmetry_snap") + layout.separator() + + layout.operator("mesh.hide", text="Hide").unselected = False + layout.operator("mesh.reveal", text="Reveal") + class VIEW3D_MT_edit_mesh_select_mode(Menu): bl_label = "Mesh Select Mode" @@ -2584,21 +2809,22 @@ class VIEW3D_MT_edit_mesh_extrude(Menu): _extrude_funcs = { 'VERT': lambda layout: - layout.operator("mesh.extrude_vertices_move", text="Vertices Only"), + layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices"), 'EDGE': lambda layout: - layout.operator("mesh.extrude_edges_move", text="Edges Only"), - 'FACE': lambda layout: - layout.operator("mesh.extrude_faces_move", text="Individual Faces"), + layout.operator("mesh.extrude_edges_move", text="Extrude Edges"), 'REGION': lambda layout: - layout.operator("view3d.edit_mesh_extrude_move_normal", text="Region"), + layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces"), 'REGION_VERT_NORMAL': lambda layout: - layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Region (Vertex Normals)"), + layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals"), + 'FACE': lambda layout: + layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces"), } @staticmethod def extrude_options(context): + tool_settings = context.tool_settings + select_mode = tool_settings.mesh_select_mode mesh = context.object.data - select_mode = context.tool_settings.mesh_select_mode menu = [] if mesh.total_face_sel: @@ -2620,45 +2846,43 @@ class VIEW3D_MT_edit_mesh_extrude(Menu): class VIEW3D_MT_edit_mesh_vertices(Menu): - bl_label = "Vertices" + bl_label = "Vertex" def draw(self, context): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - with_bullet = bpy.app.build_options.bullet + layout.operator("mesh.extrude_vertices_move", text="Extrude Vertices"), + layout.operator("mesh.bevel", text="Bevel Vertices").vertex_only = True - layout.operator("mesh.merge") - layout.operator("mesh.remove_doubles") - props = layout.operator("mesh.rip_move") - props.MESH_OT_rip.use_fill = False - props = layout.operator("mesh.rip_move", text="Rip Fill") - props.MESH_OT_rip.use_fill = True - layout.operator("mesh.rip_edge_move") - layout.operator("mesh.split") - layout.operator_menu_enum("mesh.separate", "type") + layout.separator() + + layout.operator("mesh.edge_face_add", text="New Edge/Face from Vertices") layout.operator("mesh.vert_connect_path", text="Connect Vertex Path") - layout.operator("mesh.vert_connect", text="Connect Vertices") - layout.operator("transform.vert_slide", text="Slide") + layout.operator("mesh.vert_connect", text="Connect Vertex Pairs") layout.separator() - layout.operator("mesh.mark_sharp", text="Mark Sharp Edges").use_verts = True - props = layout.operator("mesh.mark_sharp", text="Clear Sharp Edges") - props.use_verts = True - props.clear = True + props = layout.operator("mesh.rip_move", text="Rip Vertices") + props.MESH_OT_rip.use_fill = False + props = layout.operator("mesh.rip_move", text="Rip Vertices and Fill") + props.MESH_OT_rip.use_fill = True + layout.operator("mesh.rip_edge_move", text="Rip Vertices and Extend") layout.separator() - layout.operator("mesh.bevel").vertex_only = True - if with_bullet: - layout.operator("mesh.convex_hull") - layout.operator("mesh.vertices_smooth") + layout.operator("transform.vert_slide", text="Slide Vertices") + layout.operator("mesh.vertices_smooth", text="Smooth Vertices") + + layout.separator() layout.operator("mesh.blend_from_shape") + layout.operator("mesh.shape_propagate_to_all", text="Propagate to Shapes") + + layout.separator() - layout.operator("object.vertex_group_smooth") - layout.operator("mesh.shape_propagate_to_all") + layout.operator("mesh.merge", text="Merge Vertices") + layout.operator("mesh.remove_doubles", text="Remove Double Vertices") layout.separator() @@ -2693,30 +2917,35 @@ class VIEW3D_MT_edit_mesh_edges_data(Menu): layout.operator("mesh.mark_sharp") layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True - layout.separator() + layout.operator("mesh.mark_sharp", text="Mark Sharp from Vertices").use_verts = True + props = layout.operator("mesh.mark_sharp", text="Clear Sharp from Vertices") + props.use_verts = True + props.clear = True if with_freestyle: + layout.separator() + layout.operator("mesh.mark_freestyle_edge").clear = False layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True - layout.separator() class VIEW3D_MT_edit_mesh_edges(Menu): - bl_label = "Edges" + bl_label = "Edge" def draw(self, context): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.edge_face_add") - layout.operator("mesh.subdivide") - layout.operator("mesh.subdivide_edgering") - layout.operator("mesh.unsubdivide") + layout.operator("mesh.extrude_edges_move", text="Extrude Edges"), + layout.operator("mesh.bevel", text="Bevel Edges").vertex_only = False + layout.operator("mesh.bridge_edge_loops") layout.separator() - layout.menu("VIEW3D_MT_edit_mesh_edges_data") + layout.operator("mesh.subdivide") + layout.operator("mesh.subdivide_edgering") + layout.operator("mesh.unsubdivide") layout.separator() @@ -2725,22 +2954,16 @@ class VIEW3D_MT_edit_mesh_edges(Menu): layout.separator() - layout.operator("mesh.bevel").vertex_only = False + layout.operator("transform.edge_slide") layout.operator("mesh.edge_split") - layout.operator("mesh.bridge_edge_loops") layout.separator() - layout.operator("transform.edge_slide") - layout.operator("mesh.loop_multi_select", text="Edge Loops").ring = False - layout.operator("mesh.loop_multi_select", text="Edge Rings").ring = True - layout.operator("mesh.loop_to_region") - layout.operator("mesh.region_to_loop") + layout.menu("VIEW3D_MT_edit_mesh_edges_data") -class VIEW3D_MT_edit_mesh_faces(Menu): - bl_label = "Faces" - bl_idname = "VIEW3D_MT_edit_mesh_faces" +class VIEW3D_MT_edit_mesh_faces_data(Menu): + bl_label = "Face Data" def draw(self, context): layout = self.layout @@ -2749,48 +2972,69 @@ class VIEW3D_MT_edit_mesh_faces(Menu): layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.flip_normals") - layout.operator("mesh.edge_face_add") - layout.operator("mesh.fill") - layout.operator("mesh.fill_grid") - layout.operator("mesh.beautify_fill") - layout.operator("mesh.inset") - layout.operator("mesh.bevel").vertex_only = False - layout.operator("mesh.solidify") - layout.operator("mesh.intersect") - layout.operator("mesh.intersect_boolean") - layout.operator("mesh.wireframe") + layout.operator("mesh.colors_rotate") + layout.operator("mesh.colors_reverse") + + layout.separator() + + layout.operator("mesh.uvs_rotate") + layout.operator("mesh.uvs_reverse") layout.separator() if with_freestyle: layout.operator("mesh.mark_freestyle_face").clear = False layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True - layout.separator() + +class VIEW3D_MT_edit_mesh_faces(Menu): + bl_label = "Face" + bl_idname = "VIEW3D_MT_edit_mesh_faces" + + def draw(self, context): + layout = self.layout + + with_freestyle = bpy.app.build_options.freestyle + + layout.operator_context = 'INVOKE_REGION_WIN' + + layout.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Faces"), + layout.operator("view3d.edit_mesh_extrude_move_shrink_fatten", text="Extrude Faces Along Normals"), + layout.operator("mesh.extrude_faces_move", text="Extrude Individual Faces"), + + layout.separator() + + layout.operator("mesh.inset") layout.operator("mesh.poke") props = layout.operator("mesh.quads_convert_to_tris") props.quad_method = props.ngon_method = 'BEAUTY' layout.operator("mesh.tris_convert_to_quads") - layout.operator("mesh.face_split_by_edges") + layout.operator("mesh.solidify", text="Solidify Faces") + layout.operator("mesh.wireframe") layout.separator() - layout.operator("mesh.faces_shade_smooth") - layout.operator("mesh.faces_shade_flat") + layout.operator("mesh.fill") + layout.operator("mesh.fill_grid") + layout.operator("mesh.beautify_fill") - layout.operator("mesh.normals_make_consistent", text="Recalculate Normals").inside = False + layout.separator() + + layout.operator("mesh.intersect") + layout.operator("mesh.intersect_boolean") layout.separator() - layout.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False + layout.operator("mesh.face_split_by_edges") layout.separator() - layout.operator("mesh.uvs_rotate") - layout.operator("mesh.uvs_reverse") - layout.operator("mesh.colors_rotate") - layout.operator("mesh.colors_reverse") + layout.operator("mesh.faces_shade_smooth") + layout.operator("mesh.faces_shade_flat") + + layout.separator() + + layout.menu("VIEW3D_MT_edit_mesh_faces_data") class VIEW3D_MT_edit_mesh_normals(Menu): @@ -2805,6 +3049,61 @@ class VIEW3D_MT_edit_mesh_normals(Menu): layout.separator() layout.operator("mesh.flip_normals") + layout.operator("mesh.set_normals_from_faces", text="Set From Faces") + + layout.operator("transform.rotate_normal", text="Rotate Normal") + layout.operator("mesh.point_normals", text="Point normals to target") + + layout.operator("mesh.merge_normals", text="Merge") + layout.operator("mesh.split_normals", text="Split") + + layout.operator("mesh.average_normals", text="Average Normals") + + layout.label(text="Normal Vector") + + layout.operator("mesh.normals_tools", text="Copy").mode = 'COPY' + layout.operator("mesh.normals_tools", text="Paste").mode = 'PASTE' + + layout.operator("mesh.normals_tools", text="Multiply").mode = 'MULTIPLY' + layout.operator("mesh.normals_tools", text="Add").mode = 'ADD' + + layout.operator("mesh.normals_tools", text="Reset").mode = 'RESET' + + layout.operator("mesh.smoothen_normals", text="Smoothen") + + layout.label(text="Face Strength") + layout.operator("mesh.mod_weighted_strength", text="Face select", icon = "FACESEL").set = False + layout.operator("mesh.mod_weighted_strength", text="Set Strength", icon = "ZOOMIN").set = True + + +class VIEW3D_MT_edit_mesh_shading(Menu): + bl_label = "Shading" + + def draw(self, context): + layout = self.layout + + layout.operator("mesh.faces_shade_smooth", text="Smooth Faces") + layout.operator("mesh.faces_shade_flat", text="Flat Faces") + + layout.separator() + + layout.operator("mesh.mark_sharp", text="Smooth Edges").clear = True + layout.operator("mesh.mark_sharp", text="Sharp Edges") + + layout.separator() + + props = layout.operator("mesh.mark_sharp", text="Smooth Vertices") + props.use_verts = True + props.clear = True + + layout.operator("mesh.mark_sharp", text="Sharp Vertices").use_verts = True + + +class VIEW3D_MT_edit_mesh_weights(Menu): + bl_label = "Weights" + + def draw(self, context): + VIEW3D_MT_paint_weight.draw_generic(self.layout, is_editmode=True) class VIEW3D_MT_edit_mesh_clean(Menu): @@ -2868,12 +3167,17 @@ class VIEW3D_MT_edit_gpencil_delete(Menu): layout.separator() - layout.operator("gpencil.dissolve") + layout.operator_enum("gpencil.dissolve", "type") layout.separator() layout.operator("gpencil.active_frames_delete_all") + layout.separator() + + layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes").mode = 'ACTIVE' + layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes all Frames").mode = 'ALL' + # Edit Curve # draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface @@ -2882,14 +3186,6 @@ class VIEW3D_MT_edit_gpencil_delete(Menu): def draw_curve(self, context): layout = self.layout - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - - layout.menu("VIEW3D_MT_edit_curve_delete") - - layout.separator() - layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_snap") @@ -2914,15 +3210,9 @@ def draw_curve(self, context): layout.separator() - layout.menu("VIEW3D_MT_edit_curve_clean") - - layout.separator() - - layout.menu("VIEW3D_MT_edit_proportional") - - layout.separator() - layout.menu("VIEW3D_MT_edit_curve_showhide") + layout.menu("VIEW3D_MT_edit_curve_clean") + layout.menu("VIEW3D_MT_edit_curve_delete") class VIEW3D_MT_edit_curve(Menu): @@ -2977,7 +3267,7 @@ class VIEW3D_MT_edit_curve_clean(Menu): class VIEW3D_MT_edit_curve_specials(Menu): - bl_label = "Specials" + bl_label = "Curve Context Menu" def draw(self, context): layout = self.layout @@ -3024,9 +3314,6 @@ class VIEW3D_MT_edit_font(Menu): def draw(self, context): layout = self.layout - # Break convention of having undo menu here, - # instead place in "Edit" menu, matching the text menu. - layout.menu("VIEW3D_MT_edit_text_chars") layout.separator() @@ -3086,14 +3373,6 @@ class VIEW3D_MT_edit_meta(Menu): def draw(self, context): layout = self.layout - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - - layout.operator("mball.delete_metaelems", text="Delete...") - - layout.separator() - layout.menu("VIEW3D_MT_transform") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_snap") @@ -3104,11 +3383,8 @@ class VIEW3D_MT_edit_meta(Menu): layout.separator() - layout.menu("VIEW3D_MT_edit_proportional") - - layout.separator() - layout.menu("VIEW3D_MT_edit_meta_showhide") + layout.operator("mball.delete_metaelems", text="Delete...") class VIEW3D_MT_edit_meta_showhide(Menu): @@ -3128,8 +3404,6 @@ class VIEW3D_MT_edit_lattice(Menu): def draw(self, context): layout = self.layout - layout.menu("VIEW3D_MT_undo_redo") - layout.separator() layout.menu("VIEW3D_MT_transform") @@ -3145,10 +3419,6 @@ class VIEW3D_MT_edit_lattice(Menu): layout.operator("object.vertex_parent_set") - layout.separator() - - layout.menu("VIEW3D_MT_edit_proportional") - class VIEW3D_MT_edit_armature(Menu): bl_label = "Armature" @@ -3159,14 +3429,6 @@ class VIEW3D_MT_edit_armature(Menu): edit_object = context.edit_object arm = edit_object.data - layout.menu("VIEW3D_MT_undo_redo") - - layout.separator() - - layout.operator("armature.delete") - - layout.separator() - layout.menu("VIEW3D_MT_transform_armature") layout.menu("VIEW3D_MT_mirror") layout.menu("VIEW3D_MT_snap") @@ -3213,9 +3475,13 @@ class VIEW3D_MT_edit_armature(Menu): layout.menu("VIEW3D_MT_bone_options_toggle", text="Bone Settings") + layout.separator() + + layout.operator("armature.delete") + class VIEW3D_MT_armature_specials(Menu): - bl_label = "Specials" + bl_label = "Armature Context Menu" def draw(self, context): layout = self.layout @@ -3272,68 +3538,138 @@ class VIEW3D_MT_edit_armature_delete(Menu): layout.operator("armature.dissolve", text="Dissolve") -# ********** GPencil Stroke Edit menu ********** +# ********** Grease Pencil Stroke menus ********** +class VIEW3D_MT_gpencil_simplify(Menu): + bl_label = "Simplify" + def draw(self, context): + layout = self.layout + layout.operator("gpencil.stroke_simplify_fixed", text="Fixed") + layout.operator("gpencil.stroke_simplify", text="Adaptative") -class VIEW3D_MT_edit_gpencil(Menu): - bl_label = "GPencil" + +class VIEW3D_MT_paint_gpencil(Menu): + bl_label = "Strokes" def draw(self, context): - toolsettings = context.tool_settings layout = self.layout - layout.menu("VIEW3D_MT_undo_redo") + layout.menu("VIEW3D_MT_gpencil_animation") + layout.menu("VIEW3D_MT_edit_gpencil_interpolate") layout.separator() - layout.menu("VIEW3D_MT_edit_gpencil_delete") + layout.operator("gpencil.delete", text="Delete Frame").type = 'FRAME' + layout.operator("gpencil.active_frames_delete_all") - layout.separator() + +class VIEW3D_MT_assign_material(Menu): + bl_label = "Assign Material" + + def draw(self, context): + layout = self.layout + ob = context.active_object + + for slot in ob.material_slots: + mat = slot.material + layout.operator("gpencil.stroke_change_color", text=mat.name).material = mat.name + + +class VIEW3D_MT_edit_gpencil(Menu): + bl_label = "Strokes" + + def draw(self, context): + tool_settings = context.tool_settings + + layout = self.layout layout.menu("VIEW3D_MT_edit_gpencil_transform") - layout.operator("transform.mirror", text="Mirror") + + layout.separator() layout.menu("GPENCIL_MT_snap") layout.separator() - layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True - layout.prop_menu_enum(toolsettings.gpencil_sculpt, "tool", text="Sculpt Brush") + layout.menu("VIEW3D_MT_gpencil_animation") layout.separator() - layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access... layout.menu("VIEW3D_MT_edit_gpencil_interpolate") layout.separator() layout.operator("gpencil.duplicate_move", text="Duplicate") layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.menu("VIEW3D_MT_gpencil_simplify") layout.separator() + layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...") + layout.operator("gpencil.stroke_split", text="Split") layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...") layout.operator("gpencil.stroke_flip", text="Flip Direction") layout.separator() layout.operator("gpencil.copy", text="Copy") - layout.operator("gpencil.paste", text="Paste") + layout.operator("gpencil.paste", text="Paste").type = 'COPY' + layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE' + + layout.separator() + + layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer") + layout.menu("VIEW3D_MT_assign_material") + layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...") + + layout.separator() + + layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...") + + layout.separator() + + layout.menu("VIEW3D_MT_edit_gpencil_delete") + layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE' + + layout.separator() + + layout.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode") + + +class VIEW3D_MT_sculpt_gpencil(Menu): + bl_label = "Strokes" + + def draw(self, context): + layout = self.layout + + layout.menu("VIEW3D_MT_edit_gpencil_transform") + + layout.separator() + layout.menu("GPENCIL_MT_snap") layout.separator() - layout.menu("VIEW3D_MT_edit_proportional") + layout.operator("gpencil.duplicate_move", text="Duplicate") + layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.menu("VIEW3D_MT_gpencil_simplify") + + layout.separator() + + layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...") + layout.operator("gpencil.stroke_split", text="Split") + layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...") + layout.operator("gpencil.stroke_flip", text="Flip Direction") layout.separator() - layout.operator("gpencil.reveal") - layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True - layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False + layout.operator("gpencil.copy", text="Copy") + layout.operator("gpencil.paste", text="Paste").type = 'COPY' + layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE' layout.separator() layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer") - layout.operator("gpencil.stroke_change_color", text="Move to Color") + layout.menu("VIEW3D_MT_assign_material") layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...") layout.separator() @@ -3341,6 +3677,36 @@ class VIEW3D_MT_edit_gpencil(Menu): layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...") +class VIEW3D_MT_weight_gpencil(Menu): + bl_label = "Weights" + + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.vertex_group_invert", text="Invert") + layout.operator("gpencil.vertex_group_smooth", text="Smooth") + + +class VIEW3D_MT_gpencil_animation(Menu): + bl_label = "Animation" + + @classmethod + def poll(cls, context): + ob = context.active_object + return ob and ob.type == 'GPENCIL' and ob.mode != 'OBJECT' + + @staticmethod + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.blank_frame_add") + layout.operator("gpencil.active_frames_delete_all", text="Delete Frame(s)") + + layout.separator() + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers").mode = 'ALL' + + class VIEW3D_MT_edit_gpencil_transform(Menu): bl_label = "Transform" @@ -3373,21 +3739,30 @@ class VIEW3D_MT_edit_gpencil_interpolate(Menu): layout.operator("gpencil.interpolate_sequence", text="Sequence") -# ********** Panel ********** +class VIEW3D_MT_object_mode_pie(Menu): + bl_label = "Mode" + def draw(self, context): + layout = self.layout -class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' + pie = layout.menu_pie() + pie.operator_enum("OBJECT_OT_mode_set", "mode") - # NOTE: this is just a wrapper around the generic GP Panel +class VIEW3D_MT_view_pie(Menu): + bl_label = "View" + bl_idname = "VIEW3D_MT_view_pie" -class VIEW3D_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator_enum("VIEW3D_OT_view_axis", "type") + pie.operator("view3d.view_camera", text="View Camera", icon='CAMERA_DATA') + pie.operator("view3d.view_selected", text="View Selected", icon='ZOOM_SELECTED') - # NOTE: this is just a wrapper around the generic GP Panel + +# ********** Panel ********** class VIEW3D_PT_view3d_properties(Panel): @@ -3400,37 +3775,65 @@ class VIEW3D_PT_view3d_properties(Panel): view = context.space_data - col = layout.column() - col.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews) - col.prop(view, "lens") - col.label(text="Lock to Object:") - col.prop(view, "lock_object", text="") - lock_object = view.lock_object - if lock_object: - if lock_object.type == 'ARMATURE': - col.prop_search(view, "lock_bone", lock_object.data, - "edit_bones" if lock_object.mode == 'EDIT' - else "bones", - text="") - else: - col.prop(view, "lock_cursor", text="Lock to Cursor") + layout.use_property_split = True + layout.use_property_decorate = False # No animation. - col = layout.column() - col.prop(view, "lock_camera") + flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True) + col = flow.column() - col = layout.column(align=True) - col.label(text="Clip:") - col.prop(view, "clip_start", text="Start") - col.prop(view, "clip_end", text="End") + subcol = col.column() + subcol.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews) + subcol.prop(view, "lens", text="Focal Length") subcol = col.column(align=True) + subcol.prop(view, "clip_start", text="Clip Start") + subcol.prop(view, "clip_end", text="End") + + subcol.separator() + + col = flow.column() + + subcol = col.column() subcol.enabled = not view.lock_camera_and_layers - subcol.label(text="Local Camera:") - subcol.prop(view, "camera", text="") + subcol.prop(view, "camera", text="Local Camera") + + subcol = col.column(align=True) + subcol.prop(view, "use_render_border") + subcol.active = view.region_3d.view_perspective != 'CAMERA' + + +class VIEW3D_PT_view3d_camera_lock(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_label = "Camera Lock" + bl_parent_id = "VIEW3D_PT_view3d_properties" + + def draw(self, context): + layout = self.layout + + layout.use_property_split = True + layout.use_property_decorate = False # No animation. + + view = context.space_data col = layout.column(align=True) - col.prop(view, "use_render_border") - col.active = view.region_3d.view_perspective != 'CAMERA' + subcol = col.column() + subcol.active = bool(view.region_3d.view_perspective != 'CAMERA' or view.region_quadviews) + + subcol.prop(view, "lock_object") + lock_object = view.lock_object + if lock_object: + if lock_object.type == 'ARMATURE': + subcol.prop_search( + view, "lock_bone", lock_object.data, + "edit_bones" if lock_object.mode == 'EDIT' + else "bones", + text="" + ) + else: + subcol.prop(view, "lock_cursor", text="Lock to 3D Cursor") + + col.prop(view, "lock_camera") class VIEW3D_PT_view3d_cursor(Panel): @@ -3440,527 +3843,1027 @@ class VIEW3D_PT_view3d_cursor(Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True view = context.space_data + layout.column().prop(view, "cursor_location", text="Location") -class VIEW3D_PT_view3d_name(Panel): +class VIEW3D_PT_object_type_visibility(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Item" + bl_region_type = 'HEADER' + bl_label = "View Object Types" + bl_ui_units_x = 6 + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + view = context.space_data + + col = layout.column() + + attr_object_types = ( + # Geometry + "mesh", + "curve", + "surf", + "meta", + "font", + None, + # Other + "armature", + "lattice", + "empty", + "grease_pencil", + "camera", + "light", + "light_probe", + "speaker", + ) + + for attr in attr_object_types: + if attr is None: + col.separator() + continue + + attr_v = "show_object_viewport_" f"{attr:s}" + attr_s = "show_object_select_" f"{attr:s}" + + icon_s = 'RESTRICT_SELECT_OFF' if getattr(view, attr_s) else 'RESTRICT_SELECT_ON' + + row = col.row(align=True) + row.prop(view, attr_v) + row.active = getattr(view, attr_v) + row.prop(view, attr_s, text="", icon=icon_s, emboss=False) + + +class VIEW3D_PT_shading(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Shading" + bl_ui_units_x = 11 + + @classmethod + def get_shading(cls, context): + # Get settings from 3D viewport or OpenGL render engine + view = context.space_data + if view.type == 'VIEW_3D': + return view.shading + else: + return context.scene.display.shading + + def draw(self, context): + pass + + +class VIEW3D_PT_shading_lighting(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Lighting" + bl_parent_id = 'VIEW3D_PT_shading' + + def draw(self, context): + layout = self.layout + shading = VIEW3D_PT_shading.get_shading(context) + + col = layout.column() + split = col.split(0.9) + + if shading.type == 'SOLID': + split.row().prop(shading, "light", expand=True) + col = split.column() + + split = layout.split(0.9) + col = split.column() + sub = col.row() + sub.scale_y = 0.6 # smaller matcap/hdri preview + + if shading.light == 'STUDIO': + sub.template_icon_view(shading, "studio_light", scale=3) + + if shading.selected_studio_light.orientation == 'WORLD': + col.prop(shading, "studiolight_rotate_z", text="Rotation") + + col = split.column() + col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') + + elif shading.light == 'MATCAP': + sub.template_icon_view(shading, "studio_light", scale=3) + + col = split.column() + col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') + col.operator('VIEW3D_OT_toggle_matcap_flip', emboss=False, text="", icon='ARROW_LEFTRIGHT') + + elif shading.type == 'MATERIAL': + col.prop(shading, "use_scene_lights") + col.prop(shading, "use_scene_world") + + if not shading.use_scene_world: + col = layout.column() + split = col.split(0.9) + + col = split.column() + sub = col.row() + sub.scale_y = 0.6 + sub.template_icon_view(shading, "studio_light", scale=3) + + col = split.column() + col.operator('wm.studiolight_userpref_show', emboss=False, text="", icon='PREFERENCES') + + if shading.selected_studio_light.orientation == 'WORLD': + split = layout.split(0.9) + col = split.column() + col.prop(shading, "studiolight_rotate_z", text="Rotation") + col.prop(shading, "studiolight_background_alpha") + col = split.column() # to align properly with above + + +class VIEW3D_PT_shading_color(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Color" + bl_parent_id = 'VIEW3D_PT_shading' @classmethod def poll(cls, context): - return (context.active_object is not None) + shading = VIEW3D_PT_shading.get_shading(context) + return shading.type == 'SOLID' def draw(self, context): layout = self.layout - ob = context.active_object - row = layout.row() - row.label(text="", icon='OBJECT_DATA') - row.prop(ob, "name", text="") + shading = VIEW3D_PT_shading.get_shading(context) - if ob.type == 'ARMATURE' and ob.mode in {'EDIT', 'POSE'}: - bone = context.active_bone - if bone: - row = layout.row() - row.label(text="", icon='BONE_DATA') - row.prop(bone, "name", text="") + layout.row().prop(shading, 'color_type', expand=True) + if shading.color_type == 'SINGLE': + layout.row().prop(shading, 'single_color', text="") + + layout.row().label("Background") + layout.row().prop(shading, 'background_type', expand=True) + if shading.background_type == 'VIEWPORT': + layout.row().prop(shading, "background_color", text="") -class VIEW3D_PT_view3d_display(Panel): +class VIEW3D_PT_shading_options(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Display" - bl_options = {'DEFAULT_CLOSED'} + bl_region_type = 'HEADER' + bl_label = "Options" + bl_parent_id = 'VIEW3D_PT_shading' + + @classmethod + def poll(cls, context): + shading = VIEW3D_PT_shading.get_shading(context) + return shading.type == 'SOLID' def draw(self, context): layout = self.layout - view = context.space_data - scene = context.scene + shading = VIEW3D_PT_shading.get_shading(context) col = layout.column() - col.prop(view, "show_only_render") - col.prop(view, "show_world") + + is_xray = shading.show_xray + is_shadows = shading.show_shadows + + icon_x = 'CHECKBOX_HLT' if is_xray else 'CHECKBOX_DEHLT' + row = col.row() + row.prop(shading, "show_xray", text="") + sub = row.row() + sub.active = is_xray + sub.prop(shading, "xray_alpha", text="X-Ray") + + icon_s = 'CHECKBOX_HLT' if is_shadows else 'CHECKBOX_DEHLT' + row = col.row() + row.prop(shading, "show_shadows", text="") + row.active = not is_xray + sub = row.row(align=True) + sub.active = is_shadows + sub.prop(shading, "shadow_intensity", text="Shadow") + sub.popover( + panel="VIEW3D_PT_shading_options_shadow", + icon='SCRIPTWIN', + text="" + ) col = layout.column() - display_all = not view.show_only_render - col.active = display_all - col.prop(view, "show_outline_selected") - col.prop(view, "show_all_objects_origin") - col.prop(view, "show_relationship_lines") + row = col.row() + row.active = not is_xray + row.prop(shading, "show_cavity") + + if shading.show_cavity: + sub = col.row(align=True) + sub.active = not shading.show_xray and shading.show_cavity + sub.prop(shading, "cavity_ridge_factor") + sub.prop(shading, "cavity_valley_factor") + sub.popover( + panel="VIEW3D_PT_shading_options_ssao", + icon='SCRIPTWIN', + text="" + ) + + row = layout.split() + row.prop(shading, "show_object_outline") + sub = row.row() + sub.active = shading.show_object_outline + sub.prop(shading, "object_outline_color", text="") col = layout.column() - col.active = display_all - split = col.split(percentage=0.55) - split.prop(view, "show_floor", text="Grid Floor") + if not shading.light == 'MATCAP': + col.prop(shading, "show_specular_highlight") - row = split.row(align=True) - row.prop(view, "show_axis_x", text="X", toggle=True) - row.prop(view, "show_axis_y", text="Y", toggle=True) - row.prop(view, "show_axis_z", text="Z", toggle=True) - sub = col.column(align=True) - sub.active = bool(view.show_floor or view.region_quadviews or not view.region_3d.is_perspective) - subsub = sub.column(align=True) - subsub.active = view.show_floor - subsub.prop(view, "grid_lines", text="Lines") - sub.prop(view, "grid_scale", text="Scale") - subsub = sub.column(align=True) - subsub.active = scene.unit_settings.system == 'NONE' - subsub.prop(view, "grid_subdivisions", text="Subdivisions") +class VIEW3D_PT_shading_options_shadow(Panel): + bl_label = "Shadow Settings" + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' - layout.separator() + @classmethod + def poll(cls, context): + return True - layout.operator("screen.region_quadview", text="Toggle Quad View") + def draw(self, context): + layout = self.layout + layout.use_property_split = True + scene = context.scene - if view.region_quadviews: - region = view.region_quadviews[2] - col = layout.column() - col.prop(region, "lock_rotation") - row = col.row() - row.enabled = region.lock_rotation - row.prop(region, "show_sync_view") - row = col.row() - row.enabled = region.lock_rotation and region.show_sync_view - row.prop(region, "use_box_clip") + col = layout.column() + col.prop(scene.display, "light_direction") + col.prop(scene.display, "shadow_shift") -class VIEW3D_PT_view3d_stereo(Panel): +class VIEW3D_PT_shading_options_ssao(Panel): + bl_label = "SSAO Settings" bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Stereoscopy" - bl_options = {'DEFAULT_CLOSED'} + bl_region_type = 'HEADER' @classmethod def poll(cls, context): + return True + + def draw(self, context): + layout = self.layout + layout.use_property_split = True scene = context.scene - return scene.render.use_multiview + + col = layout.column(align=True) + col.prop(scene.display, "matcap_ssao_samples") + col.prop(scene.display, "matcap_ssao_distance") + col.prop(scene.display, "matcap_ssao_attenuation") + + +class VIEW3D_PT_overlay(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Overlays" + bl_ui_units_x = 13 + + def draw(self, context): + pass + + +class VIEW3D_PT_overlay_gizmo(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Gizmo" + + def draw_header(self, context): + view = context.space_data + self.layout.prop(view, "show_gizmo", text="") def draw(self, context): layout = self.layout + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays - basic_stereo = context.scene.render.views_format == 'STEREO_3D' + col = layout.column() + col.active = display_all + + row = col.row(align=True) + row.active = view.show_gizmo + row.prop(view, "show_gizmo_navigate", text="Navigate", toggle=True) + row.prop(view, "show_gizmo_context", text="Active Object", toggle=True) + row.prop(view, "show_gizmo_tool", text="Active Tools", toggle=True) + + +class VIEW3D_PT_overlay_guides(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Guides" + + def draw(self, context): + layout = self.layout + + view = context.space_data + overlay = view.overlay + shading = view.shading + display_all = overlay.show_overlays col = layout.column() - col.row().prop(view, "stereo_3d_camera", expand=True) + col.active = display_all - col.label(text="Display:") - row = col.row() - row.active = basic_stereo - row.prop(view, "show_stereo_3d_cameras") - row = col.row() - row.active = basic_stereo - split = row.split() - split.prop(view, "show_stereo_3d_convergence_plane") - split = row.split() - split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha") - split.active = view.show_stereo_3d_convergence_plane - row = col.row() - split = row.split() - split.prop(view, "show_stereo_3d_volume") - split = row.split() - split.prop(view, "stereo_3d_volume_alpha", text="Alpha") + split = col.split() + sub = split.column() + sub.prop(overlay, "show_floor", text="Grid") + + if overlay.show_floor: + sub = col.column(align=True) + sub.active = bool(overlay.show_floor or view.region_quadviews or not view.region_3d.is_perspective) + subsub = sub.row(align=True) + subsub.active = overlay.show_floor + subsub.prop(overlay, "grid_scale", text="Scale") + subsub.prop(overlay, "grid_subdivisions", text="Subdivisions") + + sub = split.column() + row = sub.row() + row.label(text="Axes") + + subrow = row.row(align=True) + subrow.prop(overlay, "show_axis_x", text="X", toggle=True) + subrow.prop(overlay, "show_axis_y", text="Y", toggle=True) + subrow.prop(overlay, "show_axis_z", text="Z", toggle=True) + + split = col.split() + sub = split.column() + sub.prop(overlay, "show_text", text="Text Info") + sub = split.column() + sub.prop(overlay, "show_cursor", text="3D Cursor") + + if shading.type == 'MATERIAL': + col.prop(overlay, "show_look_dev") + + col.prop(overlay, "show_annotation", text="Annotations") -class VIEW3D_PT_view3d_shading(Panel): +class VIEW3D_PT_overlay_object(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Shading" + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Objects" def draw(self, context): layout = self.layout + view = context.space_data + overlay = view.overlay + shading = view.shading + display_all = overlay.show_overlays + + col = layout.column(align=True) + col.active = display_all + + split = col.split() + + sub = split.column(align=True) + sub.prop(overlay, "show_ornaments", text="Ornaments") + sub.prop(overlay, "show_relationship_lines") + sub.prop(overlay, "show_outline_selected") + + sub = split.column(align=True) + sub.prop(overlay, "show_bones", text="Bones") + sub.prop(overlay, "show_motion_paths") + sub.prop(overlay, "show_object_origins", text="Origins") + subsub = sub.column() + subsub.active = overlay.show_object_origins + subsub.prop(overlay, "show_object_origins_all", text="Origins (All)") + +class VIEW3D_PT_overlay_geometry(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Geometry" + + def draw(self, context): + layout = self.layout view = context.space_data - scene = context.scene - gs = scene.game_settings - obj = context.object + overlay = view.overlay + display_all = overlay.show_overlays col = layout.column() + col.active = display_all + + row = col.row() + row.prop(overlay, "show_wireframes", text="") + sub = row.row() + sub.active = overlay.show_wireframes + sub.prop(overlay, "wireframe_threshold", text="Wireframe") + + col = layout.column(align=True) + col.active = display_all + + split = col.split() + sub = split.column(align=True) + sub.prop(overlay, "show_backface_culling") - if not scene.render.use_shading_nodes: - col.prop(gs, "material_mode", text="") - - if view.viewport_shade == 'SOLID': - col.prop(view, "show_textured_solid") - col.prop(view, "use_matcap") - if view.use_matcap: - col.template_icon_view(view, "matcap_icon") - if view.viewport_shade == 'TEXTURED' or context.mode == 'PAINT_TEXTURE': - if scene.render.use_shading_nodes or gs.material_mode != 'GLSL': - col.prop(view, "show_textured_shadeless") - - col.prop(view, "show_backface_culling") - - if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}: - if obj and obj.mode == 'EDIT': - col.prop(view, "show_occlude_wire") - - fx_settings = view.fx_settings - - if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'}: - sub = col.column() - sub.active = view.region_3d.view_perspective == 'CAMERA' - sub.prop(fx_settings, "use_dof") - col.prop(fx_settings, "use_ssao", text="Ambient Occlusion") - 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") - - -class VIEW3D_PT_view3d_motion_tracking(Panel): + sub = split.column(align=True) + #sub.prop(overlay, "show_onion_skins") + sub.prop(overlay, "show_face_orientation") + + +class VIEW3D_PT_overlay_motion_tracking(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' bl_label = "Motion Tracking" - bl_options = {'DEFAULT_CLOSED'} def draw_header(self, context): view = context.space_data - self.layout.prop(view, "show_reconstruction", text="") def draw(self, context): layout = self.layout - view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays col = layout.column() - col.active = view.show_reconstruction - col.prop(view, "show_camera_path", text="Camera Path") - col.prop(view, "show_bundle_names", text="3D Marker Names") - col.label(text="Track Type and Size:") - row = col.row(align=True) - row.prop(view, "tracks_draw_type", text="") - row.prop(view, "tracks_draw_size", text="") + col.active = display_all + + if view.show_reconstruction: + split = col.split() + + sub = split.column(align=True) + sub.active = view.show_reconstruction + sub.prop(view, "show_camera_path", text="Camera Path") + + sub = split.column() + sub.prop(view, "show_bundle_names", text="Marker Names") + + col = layout.column() + col.label(text="Tracks:") + row = col.row(align=True) + row.prop(view, "tracks_draw_type", text="") + row.prop(view, "tracks_draw_size", text="Size") -class VIEW3D_PT_view3d_meshdisplay(Panel): +class VIEW3D_PT_overlay_edit_mesh(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Mesh Display" + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Mesh Edit Mode" @classmethod def poll(cls, context): - # The active object check is needed because of local-mode - return (context.active_object and (context.mode == 'EDIT_MESH')) + return context.mode == 'EDIT_MESH' def draw(self, context): layout = self.layout + + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays + data = context.active_object.data with_freestyle = bpy.app.build_options.freestyle - mesh = context.active_object.data - scene = context.scene + col = layout.column() + col.active = display_all - split = layout.split() + split = col.split() - col = split.column() - col.label(text="Overlays:") - col.prop(mesh, "show_faces", text="Faces") - col.prop(mesh, "show_edges", text="Edges") - col.prop(mesh, "show_edge_crease", text="Creases") - if with_freestyle: - col.prop(mesh, "show_edge_seams", text="Seams") + sub = split.column() + sub.prop(data, "show_edges", text="Edges") + sub = split.column() + sub.prop(data, "show_faces", text="Faces") - layout.prop(mesh, "show_weight") + row = col.row(align=True) + row.prop(data, "show_edge_crease", text="Creases", toggle=True) + row.prop(data, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural, toggle=True) + row.prop(data, "show_edge_bevel_weight", text="Bevel", toggle=True) - col = split.column() - col.label() if not with_freestyle: - col.prop(mesh, "show_edge_seams", text="Seams") - col.prop(mesh, "show_edge_sharp", text="Sharp", text_ctxt=i18n_contexts.plural) - col.prop(mesh, "show_edge_bevel_weight", text="Bevel") - if with_freestyle: - col.prop(mesh, "show_freestyle_edge_marks", text="Edge Marks") - col.prop(mesh, "show_freestyle_face_marks", text="Face Marks") + row.prop(data, "show_edge_seams", text="Seams", toggle=True) - col = layout.column() - col.separator() - col.label(text="Normals:") - row = col.row(align=True) +class VIEW3D_PT_overlay_edit_mesh_shading(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh' + bl_label = "Shading" - row.prop(mesh, "show_normal_vertex", text="", icon='VERTEXSEL') - row.prop(mesh, "show_normal_loop", text="", icon='LOOPSEL') - row.prop(mesh, "show_normal_face", text="", icon='FACESEL') + @classmethod + def poll(cls, context): + return context.mode == 'EDIT_MESH' - sub = row.row(align=True) - sub.active = mesh.show_normal_vertex or mesh.show_normal_face or mesh.show_normal_loop - sub.prop(scene.tool_settings, "normal_size", text="Size") + def draw(self, context): + layout = self.layout - col.separator() - split = layout.split() - col = split.column() - col.label(text="Edge Info:") - col.prop(mesh, "show_extra_edge_length", text="Length") - col.prop(mesh, "show_extra_edge_angle", text="Angle") - col = split.column() - col.label(text="Face Info:") - col.prop(mesh, "show_extra_face_area", text="Area") - col.prop(mesh, "show_extra_face_angle", text="Angle") - if context.user_preferences.view.show_developer_ui: - layout.prop(mesh, "show_extra_indices") - - -class VIEW3D_PT_view3d_meshstatvis(Panel): + view = context.space_data + overlay = view.overlay + tool_settings = context.tool_settings + display_all = overlay.show_overlays + data = context.active_object.data + statvis = tool_settings.statvis + + col = layout.column() + col.active = display_all + + col.prop(overlay, "show_occlude_wire") + + col.prop(overlay, "show_weight", text="Vertex Group Weights") + if overlay.show_weight: + row = col.split() + row.label(text="Zero Weights") + row.prop(tool_settings, "vertex_group_user", text="") + + col.prop(data, "show_statvis", text="Mesh Analysis") + if data.show_statvis: + col = col.column() + + sub = col.split() + sub.active = data.show_statvis + sub.label(text="Type") + sub.prop(statvis, "type", text="") + + statvis_type = statvis.type + if statvis_type == 'OVERHANG': + row = col.row(align=True) + row.prop(statvis, "overhang_min", text="Minimum") + row.prop(statvis, "overhang_max", text="Maximum") + col.row().prop(statvis, "overhang_axis", expand=True) + elif statvis_type == 'THICKNESS': + row = col.row(align=True) + row.prop(statvis, "thickness_min", text="Minimum") + row.prop(statvis, "thickness_max", text="Maximum") + col.prop(statvis, "thickness_samples") + elif statvis_type == 'INTERSECT': + pass + elif statvis_type == 'DISTORT': + row = col.row(align=True) + row.prop(statvis, "distort_min", text="Minimum") + row.prop(statvis, "distort_max", text="Maximum") + elif statvis_type == 'SHARP': + row = col.row(align=True) + row.prop(statvis, "sharp_min", text="Minimum") + row.prop(statvis, "sharp_max", text="Maximum") + + +class VIEW3D_PT_overlay_edit_mesh_measurement(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Mesh Analysis" + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh' + bl_label = "Measurement" @classmethod def poll(cls, context): - # The active object check is needed because of local-mode - return (context.active_object and (context.mode == 'EDIT_MESH')) + return context.mode == 'EDIT_MESH' - def draw_header(self, context): - mesh = context.active_object.data + def draw(self, context): + layout = self.layout + + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays + data = context.active_object.data + + col = layout.column() + col.active = display_all + + split = col.split() + + sub = split.column() + sub.prop(data, "show_extra_edge_length", text="Edge Length") + sub.prop(data, "show_extra_edge_angle", text="Edge Angle") - self.layout.prop(mesh, "show_statvis", text="") + sub = split.column() + sub.prop(data, "show_extra_face_area", text="Face Area") + sub.prop(data, "show_extra_face_angle", text="Face Angle") + + +class VIEW3D_PT_overlay_edit_mesh_normals(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh' + bl_label = "Normals" + + @classmethod + def poll(cls, context): + return context.mode == 'EDIT_MESH' def draw(self, context): layout = self.layout - mesh = context.active_object.data - statvis = context.tool_settings.statvis - layout.active = mesh.show_statvis + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays - layout.prop(statvis, "type") - statvis_type = statvis.type - if statvis_type == 'OVERHANG': - row = layout.row(align=True) - row.prop(statvis, "overhang_min", text="") - row.prop(statvis, "overhang_max", text="") - layout.row().prop(statvis, "overhang_axis", expand=True) - elif statvis_type == 'THICKNESS': - row = layout.row(align=True) - row.prop(statvis, "thickness_min", text="") - row.prop(statvis, "thickness_max", text="") - layout.prop(statvis, "thickness_samples") - elif statvis_type == 'INTERSECT': - pass - elif statvis_type == 'DISTORT': - row = layout.row(align=True) - row.prop(statvis, "distort_min", text="") - row.prop(statvis, "distort_max", text="") - elif statvis_type == 'SHARP': - row = layout.row(align=True) - row.prop(statvis, "sharp_min", text="") - row.prop(statvis, "sharp_max", text="") + col = layout.column() + col.active = display_all + + row = col.row(align=True) + row.prop(overlay, "show_vertex_normals", text="", icon='VERTEXSEL') + row.prop(overlay, "show_split_normals", text="", icon='LOOPSEL') + row.prop(overlay, "show_face_normals", text="", icon='FACESEL') + + sub = row.row(align=True) + sub.active = overlay.show_vertex_normals or overlay.show_face_normals or overlay.show_split_normals + sub.prop(overlay, "normals_length", text="Size") -class VIEW3D_PT_view3d_curvedisplay(Panel): +class VIEW3D_PT_overlay_edit_mesh_freestyle(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Curve Display" + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Freestyle" @classmethod def poll(cls, context): - return (context.mode == 'EDIT_CURVE') + return context.mode == 'EDIT_MESH' and bpy.app.build_options.freestyle def draw(self, context): layout = self.layout - curve = context.active_object.data + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays + data = context.active_object.data col = layout.column() + col.active = display_all + row = col.row() - row.prop(curve, "show_handles", text="Handles") - row.prop(curve, "show_normal_face", text="Normals") - col.prop(context.scene.tool_settings, "normal_size", text="Normal Size") + row.prop(data, "show_freestyle_edge_marks", text="Edge Marks") + row.prop(data, "show_freestyle_face_marks", text="Face Marks") + row.prop(data, "show_edge_seams", text="Seams") -class VIEW3D_PT_background_image(Panel): +class VIEW3D_PT_overlay_edit_mesh_developer(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Background Images" - bl_options = {'DEFAULT_CLOSED'} + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay_edit_mesh' + bl_label = "Developer" - def draw_header(self, context): + @classmethod + def poll(cls, context): + return context.mode == 'EDIT_MESH' and context.user_preferences.view.show_developer_ui + + def draw(self, context): + layout = self.layout + + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays + data = context.active_object.data + + col = layout.column() + col.active = display_all + + col.prop(data, "show_extra_indices", text="Indices") + + +class VIEW3D_PT_overlay_edit_curve(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Curve Edit Mode" + + @classmethod + def poll(cls, context): + return context.mode == 'EDIT_CURVE' + + def draw(self, context): + layout = self.layout view = context.space_data + data = context.active_object.data + overlay = view.overlay + display_all = overlay.show_overlays + + col = layout.column() + col.active = display_all + + row = col.row() + row.prop(data, "show_handles", text="Handles") + row.prop(data, "show_normal_face", text="Normals") + + +class VIEW3D_PT_overlay_sculpt(Panel): + bl_space_type = 'VIEW_3D' + bl_context = ".sculpt_mode" + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Sculpt" + + @classmethod + def poll(cls, context): + return ( + context.mode == 'SCULPT' and + (context.sculpt_object and context.tool_settings.sculpt) + ) + + def draw(self, context): + layout = self.layout + tool_settings = context.tool_settings + sculpt = tool_settings.sculpt + + layout.prop(sculpt, "show_diffuse_color") + layout.prop(sculpt, "show_mask") - self.layout.prop(view, "show_background_images", text="") + +class VIEW3D_PT_overlay_pose(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Pose Mode" + + @classmethod + def poll(cls, context): + return context.mode == 'POSE' def draw(self, context): layout = self.layout + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays + + col = layout.column() + col.active = display_all + col.prop(overlay, "show_transparent_bones") + + row = col.row() + row.prop(overlay, "show_bone_select", text="") + sub = row.row() + sub.active = display_all and overlay.show_bone_select + sub.prop(overlay, "bone_select_alpha", text="Fade Geometry") + + +class VIEW3D_PT_overlay_edit_armature(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "Armature Edit Mode" + + @classmethod + def poll(cls, context): + return context.mode == 'EDIT_ARMATURE' + def draw(self, context): + layout = self.layout view = context.space_data - use_multiview = context.scene.render.use_multiview + overlay = view.overlay + display_all = overlay.show_overlays col = layout.column() - col.operator("view3d.background_image_add", text="Add Image") - - for i, bg in enumerate(view.background_images): - layout.active = view.show_background_images - box = layout.box() - row = box.row(align=True) - row.prop(bg, "show_expanded", text="", emboss=False) - if bg.source == 'IMAGE' and bg.image: - row.prop(bg.image, "name", text="", emboss=False) - elif bg.source == 'MOVIE_CLIP' and bg.clip: - row.prop(bg.clip, "name", text="", emboss=False) - else: - row.label(text="Not Set") + col.active = display_all + col.prop(overlay, "show_transparent_bones") - if bg.show_background_image: - row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_OFF') - else: - row.prop(bg, "show_background_image", text="", emboss=False, icon='RESTRICT_VIEW_ON') - row.operator("view3d.background_image_remove", text="", emboss=False, icon='X').index = i +class VIEW3D_PT_overlay_paint(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "" + + @classmethod + def poll(cls, context): + return context.mode in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'} + + def draw_header(self, context): + layout = self.layout + layout.label(text={ + 'PAINT_TEXTURE': "Texture Paint", + 'PAINT_VERTEX': "Vertex Paint", + 'PAINT_WEIGHT': "Weight Paint", + }[context.mode]) + + def draw(self, context): + layout = self.layout + view = context.space_data + overlay = view.overlay + display_all = overlay.show_overlays + + col = layout.column() + col.active = display_all - box.prop(bg, "view_axis", text="Axis") + col.prop(overlay, { + 'PAINT_TEXTURE': "texture_paint_mode_opacity", + 'PAINT_VERTEX': "vertex_paint_mode_opacity", + 'PAINT_WEIGHT': "weight_paint_mode_opacity", + }[context.mode], text="Opacity") - if bg.show_expanded: - row = box.row() - row.prop(bg, "source", expand=True) + if context.mode in {'PAINT_WEIGHT', 'PAINT_VERTEX'}: + col.prop(overlay, "show_paint_wire") - has_bg = False - if bg.source == 'IMAGE': - row = box.row() - row.template_ID(bg, "image", open="image.open") - if bg.image is not None: - box.template_image(bg, "image", bg.image_user, compact=True) - has_bg = True - if use_multiview and bg.view_axis in {'CAMERA', 'ALL'}: - box.prop(bg.image, "use_multiview") +class VIEW3D_PT_pivot_point(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Pivot Point" + bl_ui_units_x = 8 - column = box.column() - column.active = bg.image.use_multiview + def draw(self, context): + toolsettings = context.tool_settings + obj = context.active_object + mode = context.mode - column.label(text="Views Format:") - column.row().prop(bg.image, "views_format", expand=True) + layout = self.layout + col = layout.column() + col.label("Pivot Point") + col.prop(toolsettings, "transform_pivot_point", expand=True) - sub = column.box() - sub.active = bg.image.views_format == 'STEREO_3D' - sub.template_image_stereo_3d(bg.image.stereo_3d_format) + if (obj is None) or (mode in {'OBJECT', 'POSE', 'WEIGHT_PAINT'}): + col.separator() - elif bg.source == 'MOVIE_CLIP': - box.prop(bg, "use_camera_clip") + col.prop( + toolsettings, + "use_transform_pivot_point_align", + text="Center Points Only", + ) - column = box.column() - column.active = not bg.use_camera_clip - column.template_ID(bg, "clip", open="clip.open") - if bg.clip: - column.template_movieclip(bg, "clip", compact=True) +class VIEW3D_PT_snapping(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Snapping" - if bg.use_camera_clip or bg.clip: - has_bg = True + def draw(self, context): + toolsettings = context.tool_settings + snap_elements = toolsettings.snap_elements + obj = context.active_object + mode = context.mode + object_mode = 'OBJECT' if obj is None else obj.mode - column = box.column() - column.active = has_bg - column.prop(bg.clip_user, "proxy_render_size", text="") - column.prop(bg.clip_user, "use_render_undistorted") + layout = self.layout + col = layout.column() + col.label("Snapping") + col.prop(toolsettings, "snap_elements", expand=True) - if has_bg: - col = box.column() - col.prop(bg, "opacity", slider=True) - col.row().prop(bg, "draw_depth", expand=True) + col.separator() + if 'INCREMENT' in snap_elements: + col.prop(toolsettings, "use_snap_grid_absolute") - if bg.view_axis in {'CAMERA', 'ALL'}: - col.row().prop(bg, "frame_method", expand=True) + if snap_elements != {'INCREMENT'}: + col.label("Target") + row = col.row(align=True) + row.prop(toolsettings, "snap_target", expand=True) - box = col.box() - row = box.row() - row.prop(bg, "offset_x", text="X") - row.prop(bg, "offset_y", text="Y") + if obj: + if object_mode == 'EDIT': + col.prop(toolsettings, "use_snap_self") + if object_mode in {'OBJECT', 'POSE', 'EDIT'}: + col.prop(toolsettings, "use_snap_align_rotation", text="Align Rotation") - row = box.row() - row.prop(bg, "use_flip_x") - row.prop(bg, "use_flip_y") + if 'FACE' in snap_elements: + col.prop(toolsettings, "use_snap_project", text="Project Elements") - row = box.row() - if bg.view_axis != 'CAMERA': - row.prop(bg, "rotation") - row.prop(bg, "size") + if 'VOLUME' in snap_elements: + col.prop(toolsettings, "use_snap_peel_object") class VIEW3D_PT_transform_orientations(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' + bl_region_type = 'HEADER' bl_label = "Transform Orientations" - bl_options = {'DEFAULT_CLOSED'} + bl_ui_units_x = 8 def draw(self, context): layout = self.layout + layout.label("Transform Orientations") - view = context.space_data - orientation = view.current_orientation + scene = context.scene + orientation = scene.current_orientation - row = layout.row(align=True) - row.prop(view, "transform_orientation", text="") - row.operator("transform.create_orientation", text="", icon='ZOOMIN') + row = layout.row() + col = row.column() + col.prop(scene, "transform_orientation", expand=True) + row.operator("transform.create_orientation", text="", icon='ZOOMIN', emboss=False).use = True if orientation: - row = layout.row(align=True) + row = layout.row(align=False) row.prop(orientation, "name", text="") - row.operator("transform.delete_orientation", text="", icon='X') + row.operator("transform.delete_orientation", text="", icon='X', emboss=False) -class VIEW3D_PT_etch_a_ton(Panel): +class VIEW3D_PT_overlay_gpencil_options(Panel): bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_label = "Skeleton Sketching" - bl_options = {'DEFAULT_CLOSED'} + bl_region_type = 'HEADER' + bl_parent_id = 'VIEW3D_PT_overlay' + bl_label = "" @classmethod def poll(cls, context): - scene = context.space_data - ob = context.active_object - return scene and ob and ob.type == 'ARMATURE' and ob.mode == 'EDIT' + return context.object and context.object.type == 'GPENCIL' def draw_header(self, context): layout = self.layout - toolsettings = context.scene.tool_settings + layout.label(text={ + 'GPENCIL_PAINT': "Draw Grease Pencil", + 'GPENCIL_EDIT': "Edit Grease Pencil", + 'GPENCIL_SCULPT': "Sculpt Grease Pencil", + 'GPENCIL_WEIGHT': "Weight Grease Pencil", + 'OBJECT': "Grease Pencil", + }[context.mode]) + + def draw(self, context): + layout = self.layout + view = context.space_data + overlay = view.overlay + + layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin") + + col = layout.column() + row = col.row() + row.prop(overlay, "use_gpencil_paper", text="") + sub = row.row() + sub.active = overlay.use_gpencil_paper + sub.prop(overlay, "gpencil_paper_opacity", text="Fade 3D Objects", slider=True) + + col = layout.column() + row = col.row() + row.prop(overlay, "use_gpencil_grid", text="") + sub = row.row() + sub.active = overlay.use_gpencil_grid + sub.prop(overlay, "gpencil_grid_opacity", text="Canvas Grid", slider=True) + + if overlay.use_gpencil_grid: + row = layout.row(align=True) + row.prop(overlay, "gpencil_grid_scale") + col = row.column() + col.prop(overlay, "gpencil_grid_lines", text="Subdivisions") + col.prop(overlay, "gpencil_grid_axis") + + if context.object.mode in {'GPENCIL_EDIT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}: + layout.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines") + layout.prop(overlay, "use_gpencil_multiedit_line_only", text="Show Edit Lines only in multiframe") + layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True) + + +class VIEW3D_PT_quad_view(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_label = "Quad View" + bl_options = {'DEFAULT_CLOSED'} - layout.prop(toolsettings, "use_bone_sketching", text="") + @classmethod + def poll(cls, context): + view = context.space_data + return view.region_quadviews def draw(self, context): layout = self.layout - toolsettings = context.scene.tool_settings + view = context.space_data + region = view.region_quadviews[2] col = layout.column() + col.prop(region, "lock_rotation") + row = col.row() + row.enabled = region.lock_rotation + row.prop(region, "show_sync_view") + row = col.row() + row.enabled = region.lock_rotation and region.show_sync_view + row.prop(region, "use_box_clip") - col.prop(toolsettings, "use_etch_quick") - col.prop(toolsettings, "use_etch_overdraw") - col.separator() +# Annotation properties +class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' - col.prop(toolsettings, "etch_convert_mode") + # NOTE: this is just a wrapper around the generic GP Panel - if toolsettings.etch_convert_mode == 'LENGTH': - col.prop(toolsettings, "etch_length_limit") - elif toolsettings.etch_convert_mode == 'ADAPTIVE': - col.prop(toolsettings, "etch_adaptive_limit") - elif toolsettings.etch_convert_mode == 'FIXED': - col.prop(toolsettings, "etch_subdivision_number") - elif toolsettings.etch_convert_mode == 'RETARGET': - col.prop(toolsettings, "etch_template") - col.prop(toolsettings, "etch_roll_mode") - col.separator() +class VIEW3D_PT_view3d_stereo(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_label = "Stereoscopy" + bl_options = {'DEFAULT_CLOSED'} - colsub = col.column(align=True) - colsub.prop(toolsettings, "use_etch_autoname") - sub = colsub.column(align=True) - sub.enabled = not toolsettings.use_etch_autoname - sub.prop(toolsettings, "etch_number") - sub.prop(toolsettings, "etch_side") + @classmethod + def poll(cls, context): + scene = context.scene - col.separator() + multiview = scene.render.use_multiview + return multiview + + def draw(self, context): + layout = self.layout + view = context.space_data + + basic_stereo = context.scene.render.views_format == 'STEREO_3D' - col.operator("sketch.convert", text="Convert to Bones") - col.operator("sketch.delete", text="Delete Strokes") + col = layout.column() + col.row().prop(view, "stereo_3d_camera", expand=True) + + col.label(text="Display:") + row = col.row() + row.active = basic_stereo + row.prop(view, "show_stereo_3d_cameras") + row = col.row() + row.active = basic_stereo + split = row.split() + split.prop(view, "show_stereo_3d_convergence_plane") + split = row.split() + split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha") + split.active = view.show_stereo_3d_convergence_plane + row = col.row() + split = row.split() + split.prop(view, "show_stereo_3d_volume") + split = row.split() + split.prop(view, "stereo_3d_volume_alpha", text="Alpha") class VIEW3D_PT_context_properties(Panel): @@ -3972,10 +4875,10 @@ class VIEW3D_PT_context_properties(Panel): def _active_context_member(context): obj = context.object if obj: - mode = obj.mode - if mode == 'POSE': + object_mode = obj.mode + if object_mode == 'POSE': return "active_pose_bone" - elif mode == 'EDIT' and obj.type == 'ARMATURE': + elif object_mode == 'EDIT' and obj.type == 'ARMATURE': return "active_bone" else: return "object" @@ -4002,6 +4905,84 @@ class VIEW3D_PT_context_properties(Panel): rna_prop_ui.draw(self.layout, context, member, object, False) +# Grease Pencil Object - Multiframe falloff tools +class VIEW3D_PT_gpencil_multi_frame(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Multi Frame" + + @staticmethod + def draw(self, context): + gpd = context.gpencil_data + settings = context.tool_settings.gpencil_sculpt + + layout = self.layout + col = layout.column(align=True) + col.prop(settings, "use_multiframe_falloff") + + # Falloff curve + if gpd.use_multiedit and settings.use_multiframe_falloff: + layout.template_curve_mapping(settings, "multiframe_falloff_curve", brush=True) + + +class VIEW3D_MT_gpencil_edit_specials(Menu): + bl_label = "Grease Pencil Specials" + + def draw(self, context): + layout = self.layout + is_3d_view = context.space_data.type == 'VIEW_3D' + + layout.operator_context = 'INVOKE_REGION_WIN' + + layout.menu("VIEW3D_MT_assign_material") + layout.separator() + + layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.operator("gpencil.stroke_simplify_fixed", text="Simplify") + layout.operator("gpencil.stroke_simplify", text="Simplify Adaptative") + + layout.separator() + layout.menu("GPENCIL_MT_separate", text="Separate") + + layout.separator() + layout.operator("gpencil.stroke_split", text="Split") + + layout.separator() + + layout.operator("gpencil.stroke_join", text="Join").type = 'JOIN' + layout.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY' + layout.operator("gpencil.stroke_flip", text="Flip Direction") + + layout.separator() + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL' + + if is_3d_view: + layout.separator() + layout.operator("gpencil.reproject") + + +class VIEW3D_MT_gpencil_sculpt_specials(Menu): + bl_label = "Grease Pencil Specials" + + def draw(self, context): + layout = self.layout + is_3d_view = context.space_data.type == 'VIEW_3D' + + layout.operator_context = 'INVOKE_REGION_WIN' + layout.menu("VIEW3D_MT_assign_material") + layout.separator() + + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame") + layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL' + + layout.separator() + + layout.operator("gpencil.stroke_subdivide", text="Subdivide") + layout.operator("gpencil.stroke_simplify_fixed", text="Simplify") + layout.operator("gpencil.stroke_simplify", text="Simplify Adaptative") + + classes = ( VIEW3D_HT_header, VIEW3D_MT_editor_menus, @@ -4047,25 +5028,26 @@ classes = ( INFO_MT_edit_curve_add, INFO_MT_edit_armature_add, INFO_MT_armature_add, - INFO_MT_lamp_add, + INFO_MT_light_add, + INFO_MT_lightprobe_add, INFO_MT_camera_add, INFO_MT_add, - VIEW3D_MT_undo_redo, - VIEW3D_MT_object_relations, VIEW3D_MT_object, VIEW3D_MT_object_animation, + VIEW3D_MT_object_rigid_body, VIEW3D_MT_object_clear, VIEW3D_MT_object_specials, + VIEW3D_MT_object_shading, VIEW3D_MT_object_apply, + VIEW3D_MT_object_relations, VIEW3D_MT_object_parent, VIEW3D_MT_object_track, - VIEW3D_MT_object_group, + VIEW3D_MT_object_collection, VIEW3D_MT_object_constraints, VIEW3D_MT_object_quick_effects, VIEW3D_MT_object_showhide, VIEW3D_MT_make_single_user, VIEW3D_MT_make_links, - VIEW3D_MT_object_game, VIEW3D_MT_brush, VIEW3D_MT_brush_paint_modes, VIEW3D_MT_paint_vertex, @@ -4101,12 +5083,21 @@ classes = ( VIEW3D_MT_edit_mesh_edges, VIEW3D_MT_edit_mesh_edges_data, VIEW3D_MT_edit_mesh_faces, + VIEW3D_MT_edit_mesh_faces_data, VIEW3D_MT_edit_mesh_normals, + VIEW3D_MT_edit_mesh_shading, + VIEW3D_MT_edit_mesh_weights, VIEW3D_MT_edit_mesh_clean, VIEW3D_MT_edit_mesh_delete, VIEW3D_MT_edit_mesh_showhide, + VIEW3D_MT_paint_gpencil, + VIEW3D_MT_assign_material, VIEW3D_MT_edit_gpencil, VIEW3D_MT_edit_gpencil_delete, + VIEW3D_MT_sculpt_gpencil, + VIEW3D_MT_weight_gpencil, + VIEW3D_MT_gpencil_animation, + VIEW3D_MT_gpencil_simplify, VIEW3D_MT_edit_curve, VIEW3D_MT_edit_curve_ctrlpoints, VIEW3D_MT_edit_curve_segments, @@ -4127,21 +5118,45 @@ classes = ( VIEW3D_MT_edit_armature_delete, VIEW3D_MT_edit_gpencil_transform, VIEW3D_MT_edit_gpencil_interpolate, - VIEW3D_PT_grease_pencil, - VIEW3D_PT_grease_pencil_palettecolor, + VIEW3D_MT_object_mode_pie, + VIEW3D_MT_view_pie, VIEW3D_PT_view3d_properties, + VIEW3D_PT_view3d_camera_lock, VIEW3D_PT_view3d_cursor, - VIEW3D_PT_view3d_name, - VIEW3D_PT_view3d_display, + VIEW3D_PT_object_type_visibility, + VIEW3D_PT_grease_pencil, + VIEW3D_PT_gpencil_multi_frame, + VIEW3D_MT_gpencil_edit_specials, + VIEW3D_MT_gpencil_sculpt_specials, + VIEW3D_PT_quad_view, VIEW3D_PT_view3d_stereo, - VIEW3D_PT_view3d_shading, - VIEW3D_PT_view3d_motion_tracking, - VIEW3D_PT_view3d_meshdisplay, - VIEW3D_PT_view3d_meshstatvis, - VIEW3D_PT_view3d_curvedisplay, - VIEW3D_PT_background_image, + VIEW3D_PT_shading, + VIEW3D_PT_shading_lighting, + VIEW3D_PT_shading_color, + VIEW3D_PT_shading_options, + VIEW3D_PT_shading_options_shadow, + VIEW3D_PT_shading_options_ssao, + VIEW3D_PT_overlay, + VIEW3D_PT_overlay_gizmo, + VIEW3D_PT_overlay_guides, + VIEW3D_PT_overlay_object, + VIEW3D_PT_overlay_geometry, + VIEW3D_PT_overlay_motion_tracking, + VIEW3D_PT_overlay_edit_mesh, + VIEW3D_PT_overlay_edit_mesh_shading, + VIEW3D_PT_overlay_edit_mesh_measurement, + VIEW3D_PT_overlay_edit_mesh_normals, + VIEW3D_PT_overlay_edit_mesh_freestyle, + VIEW3D_PT_overlay_edit_mesh_developer, + VIEW3D_PT_overlay_edit_curve, + VIEW3D_PT_overlay_edit_armature, + VIEW3D_PT_overlay_pose, + VIEW3D_PT_overlay_paint, + VIEW3D_PT_overlay_sculpt, + VIEW3D_PT_pivot_point, + VIEW3D_PT_snapping, VIEW3D_PT_transform_orientations, - VIEW3D_PT_etch_a_ton, + VIEW3D_PT_overlay_gpencil_options, VIEW3D_PT_context_properties, ) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 41f1a64ca51..66f15f6a8ce 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -20,12 +20,9 @@ import bpy from bpy.types import Menu, Panel, UIList from .properties_grease_pencil_common import ( - GreasePencilDrawingToolsPanel, GreasePencilStrokeEditPanel, - GreasePencilInterpolatePanel, GreasePencilStrokeSculptPanel, - GreasePencilBrushPanel, - GreasePencilBrushCurvesPanel + GreasePencilAppearancePanel, ) from .properties_paint_common import ( UnifiedPaintPanel, @@ -33,11 +30,12 @@ from .properties_paint_common import ( brush_texpaint_common, brush_mask_texture_settings, ) +from bl_operators.presets import PresetMenu class View3DPanel: - bl_space_type = 'VIEW_3D' - bl_region_type = 'TOOLS' + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' # **************** standard tool clusters ****************** @@ -53,419 +51,40 @@ def draw_keyframing_tools(context, layout): # Used by vertex & weight paint def draw_vpaint_symmetry(layout, vpaint): - col = layout.column(align=True) - col.label(text="Mirror:") - row = col.row(align=True) + split = layout.split() + + col = split.column() + col.alignment = 'RIGHT' + col.label(text="Mirror") + + col = split.column() + row = col.row(align=True) row.prop(vpaint, "use_symmetry_x", text="X", toggle=True) row.prop(vpaint, "use_symmetry_y", text="Y", toggle=True) row.prop(vpaint, "use_symmetry_z", text="Z", toggle=True) col = layout.column() + col.use_property_split = True col.prop(vpaint, "radial_symmetry", text="Radial") -# ********** default tools for object-mode **************** - - -class VIEW3D_PT_tools_transform(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "objectmode" - bl_label = "Transform" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - - col = layout.column(align=True) - col.operator("transform.mirror", text="Mirror") - - -class VIEW3D_PT_tools_object(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "objectmode" - bl_label = "Edit" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.operator("object.duplicate_move", text="Duplicate") - col.operator("object.duplicate_move_linked", text="Duplicate Linked") - - col.operator("object.delete") - - obj = context.active_object - if obj: - obj_type = obj.type - - if obj_type in {'MESH', 'CURVE', 'SURFACE', 'ARMATURE'}: - col = layout.column(align=True) - col.operator("object.join") - - if obj_type in {'MESH', 'CURVE', 'SURFACE', 'ARMATURE', 'FONT', 'LATTICE'}: - col = layout.column(align=True) - col.operator_menu_enum("object.origin_set", "type", text="Set Origin") - - if obj_type in {'MESH', 'CURVE', 'SURFACE'}: - col = layout.column(align=True) - col.label(text="Shading:") - row = col.row(align=True) - row.operator("object.shade_smooth", text="Smooth") - row.operator("object.shade_flat", text="Flat") - - if obj_type == 'MESH': - col = layout.column(align=True) - col.label(text="Data Transfer:") - row = col.row(align=True) - row.operator("object.data_transfer", text="Data") - row.operator("object.datalayout_transfer", text="Data Layout") - - -class VIEW3D_PT_tools_add_object(View3DPanel, Panel): - bl_category = "Create" - bl_context = "objectmode" - bl_label = "Add Primitive" - - @staticmethod - def draw_add_mesh(layout, label=False): - if label: - layout.label(text="Primitives:") - layout.operator("mesh.primitive_plane_add", text="Plane", icon='MESH_PLANE') - layout.operator("mesh.primitive_cube_add", text="Cube", icon='MESH_CUBE') - layout.operator("mesh.primitive_circle_add", text="Circle", icon='MESH_CIRCLE') - layout.operator("mesh.primitive_uv_sphere_add", text="UV Sphere", icon='MESH_UVSPHERE') - layout.operator("mesh.primitive_ico_sphere_add", text="Ico Sphere", icon='MESH_ICOSPHERE') - layout.operator("mesh.primitive_cylinder_add", text="Cylinder", icon='MESH_CYLINDER') - layout.operator("mesh.primitive_cone_add", text="Cone", icon='MESH_CONE') - layout.operator("mesh.primitive_torus_add", text="Torus", icon='MESH_TORUS') - - if label: - layout.label(text="Special:") - else: - layout.separator() - layout.operator("mesh.primitive_grid_add", text="Grid", icon='MESH_GRID') - layout.operator("mesh.primitive_monkey_add", text="Monkey", icon='MESH_MONKEY') - - @staticmethod - def draw_add_curve(layout, label=False): - - if label: - layout.label(text="Bezier:") - layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE') - layout.operator("curve.primitive_bezier_circle_add", text="Circle", icon='CURVE_BEZCIRCLE') - - if label: - layout.label(text="Nurbs:") - else: - layout.separator() - layout.operator("curve.primitive_nurbs_curve_add", text="Nurbs Curve", icon='CURVE_NCURVE') - layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE') - layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH') - - layout.separator() - - layout.operator("curve.draw", icon='LINE_DATA') - - @staticmethod - def draw_add_surface(layout): - layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE') - layout.operator("surface.primitive_nurbs_surface_circle_add", text="Nurbs Circle", icon='SURFACE_NCIRCLE') - layout.operator("surface.primitive_nurbs_surface_surface_add", text="Nurbs Surface", icon='SURFACE_NSURFACE') - layout.operator("surface.primitive_nurbs_surface_cylinder_add", text="Nurbs Cylinder", icon='SURFACE_NCYLINDER') - layout.operator("surface.primitive_nurbs_surface_sphere_add", text="Nurbs Sphere", icon='SURFACE_NSPHERE') - layout.operator("surface.primitive_nurbs_surface_torus_add", text="Nurbs Torus", icon='SURFACE_NTORUS') - - @staticmethod - def draw_add_mball(layout): - layout.operator_enum("object.metaball_add", "type") - - @staticmethod - def draw_add_lamp(layout): - layout.operator_enum("object.lamp_add", "type") - - @staticmethod - def draw_add_other(layout): - layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT') - layout.operator("object.armature_add", text="Armature", icon='OUTLINER_OB_ARMATURE') - layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE' - layout.operator("object.empty_add", text="Empty", icon='OUTLINER_OB_EMPTY').type = 'PLAIN_AXES' - layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') - layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Mesh:") - self.draw_add_mesh(col) - - col = layout.column(align=True) - col.label(text="Curve:") - self.draw_add_curve(col) - - # not used here: - # draw_add_surface - # draw_add_mball - - col = layout.column(align=True) - col.label(text="Lamp:") - self.draw_add_lamp(col) - - col = layout.column(align=True) - col.label(text="Other:") - self.draw_add_other(col) - +# Most of these panels should not be visible in GP edit modes -class VIEW3D_PT_tools_relations(View3DPanel, Panel): - bl_category = "Relations" - bl_context = "objectmode" - bl_label = "Relations" - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - - col.label(text="Group:") - col.operator("group.create", text="New Group") - col.operator("group.objects_add_active", text="Add to Active") - col.operator("group.objects_remove", text="Remove from Group") - - col.separator() - - col.label(text="Parent:") - row = col.row(align=True) - row.operator("object.parent_set", text="Set") - row.operator("object.parent_clear", text="Clear") - - col.separator() - - col.label(text="Object Data:") - col.operator("object.make_links_data") - col.operator("object.make_single_user") - - col.separator() - - col.label(text="Linked Objects:") - col.operator("object.make_local") - col.operator("object.proxy_make") - - -class VIEW3D_PT_tools_animation(View3DPanel, Panel): - bl_category = "Animation" - bl_context = "objectmode" - bl_label = "Animation" - - def draw(self, context): - layout = self.layout - - ob = context.active_object - mpath = ob.motion_path if ob else None - - draw_keyframing_tools(context, layout) - - col = layout.column(align=True) - col.label(text="Motion Paths:") - if mpath: - row = col.row(align=True) - row.operator("object.paths_update", text="Update") - row.operator("object.paths_clear", text="", icon='X') - else: - col.operator("object.paths_calculate", text="Calculate") - - col.separator() - - col.label(text="Action:") - col.operator("nla.bake", text="Bake Action") - - -class VIEW3D_PT_tools_rigid_body(View3DPanel, Panel): - bl_category = "Physics" - bl_context = "objectmode" - bl_label = "Rigid Body Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Add/Remove:") - row = col.row(align=True) - row.operator("rigidbody.objects_add", text="Add Active").type = 'ACTIVE' - row.operator("rigidbody.objects_add", text="Add Passive").type = 'PASSIVE' - row = col.row(align=True) - row.operator("rigidbody.objects_remove", text="Remove") - - col = layout.column(align=True) - col.label(text="Object Tools:") - col.operator("rigidbody.shape_change", text="Change Shape") - col.operator("rigidbody.mass_calculate", text="Calculate Mass") - col.operator("rigidbody.object_settings_copy", text="Copy from Active") - col.operator("object.visual_transform_apply", text="Apply Transformation") - col.operator("rigidbody.bake_to_keyframes", text="Bake To Keyframes") - col.label(text="Constraints:") - col.operator("rigidbody.connect", text="Connect") +def is_not_gpencil_edit_mode(context): + is_gpmode = ( + context.active_object and + context.active_object.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'} + ) + return not is_gpmode # ********** default tools for editmode_mesh **************** -class VIEW3D_PT_tools_transform_mesh(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "mesh_edit" - bl_label = "Transform" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - col.operator("transform.shrink_fatten", text="Shrink/Fatten") - col.operator("transform.push_pull", text="Push/Pull") - - -class VIEW3D_PT_tools_meshedit(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "mesh_edit" - bl_label = "Mesh Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Deform:") - row = col.row(align=True) - row.operator("transform.edge_slide", text="Slide Edge") - row.operator("transform.vert_slide", text="Vertex") - col.operator("mesh.noise") - col.operator("mesh.vertices_smooth") - col.operator("transform.vertex_random") - - col = layout.column(align=True) - col.label(text="Add:") - - col.menu("VIEW3D_MT_edit_mesh_extrude") - col.operator("view3d.edit_mesh_extrude_move_normal", text="Extrude Region") - col.operator("view3d.edit_mesh_extrude_individual_move", text="Extrude Individual") - col.operator("mesh.inset", text="Inset Faces") - col.operator("mesh.edge_face_add") - col.operator("mesh.subdivide") - col.operator("mesh.loopcut_slide") - col.operator("mesh.offset_edge_loops_slide") - col.operator("mesh.duplicate_move", text="Duplicate") - row = col.row(align=True) - row.operator("mesh.spin") - row.operator("mesh.screw") - - row = col.row(align=True) - props = row.operator("mesh.knife_tool", text="Knife") - props.use_occlude_geometry = True - props.only_selected = False - props = row.operator("mesh.knife_tool", text="Select") - props.use_occlude_geometry = False - props.only_selected = True - col.operator("mesh.knife_project") - col.operator("mesh.bisect") - - col = layout.column(align=True) - col.label(text="Remove:") - col.menu("VIEW3D_MT_edit_mesh_delete") - col.operator_menu_enum("mesh.merge", "type") - col.operator("mesh.remove_doubles") - - -class VIEW3D_PT_tools_meshweight(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "mesh_edit" - bl_label = "Weight Tools" - bl_options = {'DEFAULT_CLOSED'} - - # Used for Weight-Paint mode and Edit-Mode - @staticmethod - def draw_generic(layout): - col = layout.column() - col.operator("object.vertex_group_normalize_all", text="Normalize All") - col.operator("object.vertex_group_normalize", text="Normalize") - col.operator("object.vertex_group_mirror", text="Mirror") - col.operator("object.vertex_group_invert", text="Invert") - col.operator("object.vertex_group_clean", text="Clean") - col.operator("object.vertex_group_quantize", text="Quantize") - col.operator("object.vertex_group_levels", text="Levels") - col.operator("object.vertex_group_smooth", text="Smooth") - col.operator("object.vertex_group_limit_total", text="Limit Total") - col.operator("object.vertex_group_fix", text="Fix Deforms") - - def draw(self, context): - layout = self.layout - self.draw_generic(layout) - - -class VIEW3D_PT_tools_add_mesh_edit(View3DPanel, Panel): - bl_category = "Create" - bl_context = "mesh_edit" - bl_label = "Add Meshes" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - - VIEW3D_PT_tools_add_object.draw_add_mesh(col, label=True) - - -class VIEW3D_PT_tools_shading(View3DPanel, Panel): - bl_category = "Shading / UVs" - bl_context = "mesh_edit" - bl_label = "Shading" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Faces:") - row = col.row(align=True) - row.operator("mesh.faces_shade_smooth", text="Smooth") - row.operator("mesh.faces_shade_flat", text="Flat") - col.label(text="Edges:") - row = col.row(align=True) - row.operator("mesh.mark_sharp", text="Smooth").clear = True - row.operator("mesh.mark_sharp", text="Sharp") - col.label(text="Vertices:") - row = col.row(align=True) - props = row.operator("mesh.mark_sharp", text="Smooth") - props.use_verts = True - props.clear = True - row.operator("mesh.mark_sharp", text="Sharp").use_verts = True - - col = layout.column(align=True) - col.label(text="Normals:") - col.operator("mesh.normals_make_consistent", text="Recalculate") - col.operator("mesh.flip_normals", text="Flip Direction") - col.operator("mesh.set_normals_from_faces", text="Set From Faces") - - -class VIEW3D_PT_tools_uvs(View3DPanel, Panel): - bl_category = "Shading / UVs" - bl_context = "mesh_edit" - bl_label = "UVs" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="UV Mapping:") - col.menu("VIEW3D_MT_uv_map", text="Unwrap") - col.operator("mesh.mark_seam").clear = False - col.operator("mesh.mark_seam", text="Clear Seam").clear = True - class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): bl_category = "Options" - bl_context = "mesh_edit" + bl_context = ".mesh_edit" # dot on purpose (access from topbar) bl_label = "Mesh Options" @classmethod @@ -493,85 +112,15 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): col.prop(tool_settings, "edge_path_live_unwrap") col.label("Double Threshold:") col.prop(tool_settings, "double_threshold", text="") + col.prop(tool_settings, "use_mesh_automerge") # , icon='AUTOMERGE_ON' - if mesh.show_weight: - col.label("Show Zero Weights:") - col.row().prop(tool_settings, "vertex_group_user", expand=True) # ********** default tools for editmode_curve **************** -class VIEW3D_PT_tools_transform_curve(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "curve_edit" - bl_label = "Transform" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - - col = layout.column(align=True) - col.operator("transform.tilt", text="Tilt") - col.operator("transform.transform", text="Shrink/Fatten").mode = 'CURVE_SHRINKFATTEN' - - -class VIEW3D_PT_tools_curveedit(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "curve_edit" - bl_label = "Curve Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Curve:") - col.operator("curve.duplicate_move", text="Duplicate") - col.operator("curve.delete") - col.operator("curve.cyclic_toggle") - col.operator("curve.switch_direction") - col.operator("curve.spline_type_set") - col.operator("curve.radius_set") - - col = layout.column(align=True) - col.label(text="Handles:") - row = col.row(align=True) - row.operator("curve.handle_type_set", text="Auto").type = 'AUTOMATIC' - row.operator("curve.handle_type_set", text="Vector").type = 'VECTOR' - row = col.row(align=True) - row.operator("curve.handle_type_set", text="Align").type = 'ALIGNED' - row.operator("curve.handle_type_set", text="Free").type = 'FREE_ALIGN' - - col = layout.column(align=True) - col.operator("curve.normals_make_consistent") - - col = layout.column(align=True) - col.label(text="Modeling:") - col.operator("curve.extrude_move", text="Extrude") - col.operator("curve.subdivide") - col.operator("curve.smooth") - col.operator("transform.vertex_random") - - -class VIEW3D_PT_tools_add_curve_edit(View3DPanel, Panel): - bl_category = "Create" - bl_context = "curve_edit" - bl_label = "Add Curves" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - - VIEW3D_PT_tools_add_object.draw_add_curve(col, label=True) - - class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel): bl_category = "Options" - bl_context = "curve_edit" + bl_context = ".curve_edit" # dot on purpose (access from topbar) bl_label = "Curve Stroke" def draw(self, context): @@ -623,128 +172,12 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel): colsub.prop(cps, "surface_plane", expand=True) -# ********** default tools for editmode_surface **************** - -class VIEW3D_PT_tools_transform_surface(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "surface_edit" - bl_label = "Transform" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - - -class VIEW3D_PT_tools_surfaceedit(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "surface_edit" - bl_label = "Surface Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Curve:") - col.operator("curve.duplicate_move", text="Duplicate") - col.operator("curve.delete") - col.operator("curve.cyclic_toggle") - col.operator("curve.switch_direction") - - col = layout.column(align=True) - col.label(text="Modeling:") - col.operator("curve.extrude", text="Extrude") - col.operator("curve.spin") - col.operator("curve.subdivide") - - col = layout.column(align=True) - col.label(text="Deform:") - col.operator("transform.vertex_random") - - -class VIEW3D_PT_tools_add_surface_edit(View3DPanel, Panel): - bl_category = "Create" - bl_context = "surface_edit" - bl_label = "Add Surfaces" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - - VIEW3D_PT_tools_add_object.draw_add_surface(col) - - -# ********** default tools for editmode_text **************** - - -class VIEW3D_PT_tools_textedit(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "text_edit" - bl_label = "Text Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Set Case:") - col.operator("font.case_set", text="To Upper").case = 'UPPER' - col.operator("font.case_set", text="To Lower").case = 'LOWER' - - col = layout.column(align=True) - col.label(text="Style:") - col.operator("font.style_toggle", text="Bold").style = 'BOLD' - col.operator("font.style_toggle", text="Italic").style = 'ITALIC' - col.operator("font.style_toggle", text="Underline").style = 'UNDERLINE' - - # ********** default tools for editmode_armature **************** -class VIEW3D_PT_tools_armatureedit_transform(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "armature_edit" - bl_label = "Transform" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - - -class VIEW3D_PT_tools_armatureedit(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "armature_edit" - bl_label = "Armature Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Bones:") - col.operator("armature.bone_primitive_add", text="Add") - col.operator("armature.duplicate_move", text="Duplicate") - col.operator("armature.delete", text="Delete") - - col = layout.column(align=True) - col.label(text="Modeling:") - col.operator("armature.extrude_move") - col.operator("armature.subdivide", text="Subdivide") - - col = layout.column(align=True) - col.label(text="Deform:") - col.operator("transform.vertex_random") - - class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel): bl_category = "Options" - bl_context = "armature_edit" + bl_context = ".armature_edit" # dot on purpose (access from topbar) bl_label = "Armature Options" def draw(self, context): @@ -753,138 +186,30 @@ class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel): self.layout.prop(arm, "use_mirror_x") -# ********** default tools for editmode_mball **************** - - -class VIEW3D_PT_tools_mballedit(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "mball_edit" - bl_label = "Meta Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Transform:") - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - - col = layout.column(align=True) - col.label(text="Deform:") - col.operator("transform.vertex_random") - - -class VIEW3D_PT_tools_add_mball_edit(View3DPanel, Panel): - bl_category = "Create" - bl_context = "mball_edit" - bl_label = "Add Metaball" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - - VIEW3D_PT_tools_add_object.draw_add_mball(col) - - -# ********** default tools for editmode_lattice **************** - - -class VIEW3D_PT_tools_latticeedit(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "lattice_edit" - bl_label = "Lattice Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Transform:") - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - - col = layout.column(align=True) - col.operator("lattice.make_regular") - - col = layout.column(align=True) - col.label(text="Deform:") - col.operator("transform.vertex_random") - - # ********** default tools for pose-mode **************** - -class VIEW3D_PT_tools_posemode(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "posemode" - bl_label = "Pose Tools" - - def draw(self, context): - layout = self.layout - - col = layout.column(align=True) - col.label(text="Transform:") - col.operator("transform.translate") - col.operator("transform.rotate") - col.operator("transform.resize", text="Scale") - - col = layout.column(align=True) - col.label(text="In-Between:") - row = col.row(align=True) - row.operator("pose.push", text="Push") - row.operator("pose.relax", text="Relax") - col.operator("pose.breakdown", text="Breakdowner") - - col = layout.column(align=True) - col.label(text="Pose:") - row = col.row(align=True) - row.operator("pose.copy", text="Copy") - row.operator("pose.paste", text="Paste") - - row = layout.row(align=True) - row.operator("pose.propagate", text="Propagate") - row.menu("VIEW3D_MT_pose_propagate", icon='TRIA_RIGHT', text="") - - col = layout.column(align=True) - col.operator("poselib.pose_add", text="Add To Library") - - draw_keyframing_tools(context, layout) - - ob = context.object - avs = ob.pose.animation_visualization - - col = layout.column(align=True) - col.label(text="Motion Paths:") - if avs.motion_path.has_motion_paths: - row = col.row(align=True) - row.operator("pose.paths_update", text="Update") - row.operator("pose.paths_clear", text="", icon='X') - else: - col.operator("pose.paths_calculate", text="Calculate") - - class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel): bl_category = "Options" - bl_context = "posemode" + bl_context = ".posemode" # dot on purpose (access from topbar) bl_label = "Pose Options" def draw(self, context): arm = context.active_object.data self.layout.prop(arm, "use_auto_ik") + self.layout.prop(arm, "use_mirror_x") # ********** default tools for paint modes **************** class View3DPaintPanel(UnifiedPaintPanel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'TOOLS' + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel): bl_category = "Tools" + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Missing Data" @classmethod @@ -930,22 +255,19 @@ class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel): col.label("Missing Canvas", icon='INFO') col.label("Add or assign a canvas image below") col.label("Canvas Image:") - # todo this should be combinded into a single row - col.template_ID(toolsettings, "canvas", open="image.open") - col.operator("image.new", text="New").gen_context = 'PAINT_CANVAS' + col.template_ID(toolsettings, "canvas", new="image.new", open="image.open") if toolsettings.missing_stencil: col.separator() col.label("Missing Stencil", icon='INFO') col.label("Add or assign a stencil image below") col.label("Stencil Image:") - # todo this should be combinded into a single row - col.template_ID(toolsettings, "stencil_image", open="image.open") - col.operator("image.new", text="New").gen_context = 'PAINT_STENCIL' + col.template_ID(toolsettings, "stencil_image", new="image.new", open="image.open") +# TODO, move to space_view3d.py class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): - bl_category = "Tools" + bl_context = ".paint_common" # dot on purpose (access from topbar) bl_label = "Brush" @classmethod @@ -967,16 +289,16 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): if context.particle_edit_object: tool = settings.tool - layout.column().prop(settings, "tool", expand=True) - if tool != 'NONE': + layout.column().prop(settings, "tool") col = layout.column() col.prop(brush, "size", slider=True) - if tool != 'ADD': + if tool == 'ADD': + col.prop(brush, "count") + else: col.prop(brush, "strength", slider=True) if tool == 'ADD': - col.prop(brush, "count") col = layout.column() col.prop(settings, "use_default_interpolate") col.prop(brush, "steps", slider=True) @@ -1199,9 +521,6 @@ class TEXTURE_UL_texpaintslots(UIList): if self.layout_type in {'DEFAULT', 'COMPACT'}: layout.prop(item, "name", text="", emboss=False, icon_value=icon) - if (not mat.use_nodes) and context.scene.render.engine in {'BLENDER_RENDER', 'BLENDER_GAME'}: - mtex_index = mat.texture_paint_slots[index].index - layout.prop(mat, "use_textures", text="", index=mtex_index) elif self.layout_type == 'GRID': layout.alignment = 'CENTER' layout.label(text="") @@ -1213,16 +532,16 @@ class VIEW3D_MT_tools_projectpaint_uvlayer(Menu): def draw(self, context): layout = self.layout - for i, tex in enumerate(context.active_object.data.uv_textures): - props = layout.operator("wm.context_set_int", text=tex.name, translate=False) - props.data_path = "active_object.data.uv_textures.active_index" + for i, uv_layer in enumerate(context.active_object.data.uv_layers): + props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False) + props.data_path = "active_object.data.uv_layers.active_index" props.value = i +# TODO, move to space_view3d.py class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): - bl_context = "imagepaint" + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Slots" - bl_category = "Slots" @classmethod def poll(cls, context): @@ -1262,26 +581,15 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): else: slot = None - if (not mat.use_nodes) and context.scene.render.engine in {'BLENDER_RENDER', 'BLENDER_GAME'}: - row = col.row(align=True) - row.operator_menu_enum("paint.add_texture_paint_slot", "type") - row.operator("paint.delete_texture_paint_slot", text="", icon='X') - - if slot: - col.prop(mat.texture_slots[slot.index], "blend_type") - col.separator() - - if slot and slot.index != -1: + if slot and slot.is_valid: col.label("UV Map:") - col.prop_search(slot, "uv_layer", ob.data, "uv_textures", text="") + col.prop_search(slot, "uv_layer", ob.data, "uv_layers", text="") elif settings.mode == 'IMAGE': mesh = ob.data - uv_text = mesh.uv_textures.active.name if mesh.uv_textures.active else "" + uv_text = mesh.uv_layers.active.name if mesh.uv_layers.active else "" col.label("Canvas Image:") - # todo this should be combinded into a single row - col.template_ID(settings, "canvas", open="image.open") - col.operator("image.new", text="New").gen_context = 'PAINT_CANVAS' + col.template_ID(settings, "canvas", new="image.new", open="image.open") col.label("UV Map:") col.menu("VIEW3D_MT_tools_projectpaint_uvlayer", text=uv_text, translate=False) @@ -1289,10 +597,10 @@ class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel): col.operator("image.save_dirty", text="Save All Images") +# TODO, move to space_view3d.py class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel): - bl_context = "imagepaint" + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Mask" - bl_category = "Slots" @classmethod def poll(cls, context): @@ -1306,6 +614,7 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True toolsettings = context.tool_settings ipaint = toolsettings.image_paint @@ -1315,23 +624,29 @@ class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel): col = layout.column() col.active = ipaint.use_stencil_layer - stencil_text = mesh.uv_texture_stencil.name if mesh.uv_texture_stencil else "" - col.label("UV Map:") - col.menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False) + stencil_text = mesh.uv_layer_stencil.name if mesh.uv_layer_stencil else "" + split = col.split(0.5) + colsub = split.column() + colsub.alignment = 'RIGHT' + colsub.label("UV Layer") + split.column().menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False) - col.label("Stencil Image:") # todo this should be combinded into a single row - col.template_ID(ipaint, "stencil_image", open="image.open") - col.operator("image.new", text="New").gen_context = 'PAINT_STENCIL' + split = col.split(0.5) + colsub = split.column() + colsub.alignment = 'RIGHT' + colsub.label("Stencil Image") + colsub = split.column() + colsub.template_ID(ipaint, "stencil_image", new="image.new", open="image.open") - col.label("Visualization:") row = col.row(align=True) - row.prop(ipaint, "stencil_color", text="") + row.prop(ipaint, "stencil_color", text="Display Color") row.prop(ipaint, "invert_stencil", text="", icon='IMAGE_ALPHA') +# TODO, move to space_view3d.py class VIEW3D_PT_tools_brush_overlay(Panel, View3DPaintPanel): - bl_category = "Options" + bl_context = ".paint_common" # dot on purpose (access from topbar) bl_label = "Overlay" @classmethod @@ -1396,8 +711,9 @@ class VIEW3D_PT_tools_brush_overlay(Panel, View3DPaintPanel): sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA') +# TODO, move to space_view3d.py class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel): - bl_category = "Tools" + bl_context = ".paint_common" # dot on purpose (access from topbar) bl_label = "Texture" bl_options = {'DEFAULT_CLOSED'} @@ -1420,9 +736,9 @@ class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel): brush_texture_settings(col, brush, context.sculpt_object) +# TODO, move to space_view3d.py class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel): - bl_category = "Tools" - bl_context = "imagepaint" + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Texture Mask" bl_options = {'DEFAULT_CLOSED'} @@ -1443,8 +759,9 @@ class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel): brush_mask_texture_settings(col, brush) +# TODO, move to space_view3d.py class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel): - bl_category = "Tools" + bl_context = ".paint_common" # dot on purpose (access from topbar) bl_label = "Stroke" bl_options = {'DEFAULT_CLOSED'} @@ -1463,12 +780,11 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel): settings = self.paint_settings(context) brush = settings.brush + layout.use_property_split = True col = layout.column() - col.label(text="Stroke Method:") - - col.prop(brush, "stroke_method", text="") + col.prop(brush, "stroke_method") if brush.use_anchor: col.separator() @@ -1498,12 +814,16 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel): if brush.sculpt_capabilities.has_jitter: col.separator() - row = col.row(align=True) + colsub = col.split(0.5) + row = colsub.row(align=True) + row.alignment = 'RIGHT' + row.label("Jitter") + row = colsub.row(align=True) row.prop(brush, "use_relative_jitter", icon_only=True) if brush.use_relative_jitter: - row.prop(brush, "jitter", slider=True) + row.prop(brush, "jitter", slider=True, text="") else: - row.prop(brush, "jitter_absolute") + row.prop(brush, "jitter_absolute", text="") row.prop(brush, "use_pressure_jitter", toggle=True, text="") if brush.sculpt_capabilities.has_smooth_stroke: @@ -1541,8 +861,9 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel): layout.prop(settings, "input_samples") +# TODO, move to space_view3d.py class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel): - bl_category = "Tools" + bl_context = ".paint_common" # dot on purpose (access from topbar) bl_label = "Curve" bl_options = {'DEFAULT_CLOSED'} @@ -1570,26 +891,31 @@ class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel): row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX' +# TODO, move to space_view3d.py class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): - bl_category = "Tools" + bl_context = ".sculpt_mode" # dot on purpose (access from topbar) bl_label = "Dyntopo" bl_options = {'DEFAULT_CLOSED'} + bl_ui_units_x = 12 @classmethod def poll(cls, context): return (context.sculpt_object and context.tool_settings.sculpt) def draw_header(self, context): + is_popover = self.is_popover layout = self.layout layout.operator( "sculpt.dynamic_topology_toggle", icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT', text="", - emboss=False, + emboss=is_popover, ) def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False toolsettings = context.tool_settings sculpt = toolsettings.sculpt @@ -1598,9 +924,10 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): col = layout.column() col.active = context.sculpt_object.use_dynamic_topology_sculpting - sub = col.column(align=True) + + sub = col.column() sub.active = (brush and brush.sculpt_tool != 'MASK') - if (sculpt.detail_type_method == 'CONSTANT'): + if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}: row = sub.row(align=True) row.prop(sculpt, "constant_detail_resolution") row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER') @@ -1608,20 +935,23 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): sub.prop(sculpt, "detail_percent") else: sub.prop(sculpt, "detail_size") - sub.prop(sculpt, "detail_refine_method", text="") - sub.prop(sculpt, "detail_type_method", text="") - col.separator() + sub.prop(sculpt, "detail_refine_method", text="Refine Method") + sub.prop(sculpt, "detail_type_method", text="Detailing") + col.prop(sculpt, "use_smooth_shading") - col.operator("sculpt.optimize") - if (sculpt.detail_type_method == 'CONSTANT'): - col.operator("sculpt.detail_flood_fill") + col.separator() + col.prop(sculpt, "symmetrize_direction") col.operator("sculpt.symmetrize") + col.operator("sculpt.optimize") + if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}: + col.operator("sculpt.detail_flood_fill") +# TODO, move to space_view3d.py class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel): - bl_category = "Options" + bl_context = ".sculpt_mode" # dot on purpose (access from topbar) bl_label = "Options" bl_options = {'DEFAULT_CLOSED'} @@ -1653,8 +983,9 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel): self.unified_paint_settings(layout, context) +# TODO, move to space_view3d.py class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel): - bl_category = "Tools" + bl_context = ".sculpt_mode" # dot on purpose (access from topbar) bl_label = "Symmetry/Lock" bl_options = {'DEFAULT_CLOSED'} @@ -1667,35 +998,55 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel): sculpt = context.tool_settings.sculpt - col = layout.column(align=True) - col.label(text="Mirror:") + split = layout.split() + + col = split.column() + col.alignment = 'RIGHT' + col.label(text="Mirror") + + col = split.column() + row = col.row(align=True) row.prop(sculpt, "use_symmetry_x", text="X", toggle=True) row.prop(sculpt, "use_symmetry_y", text="Y", toggle=True) row.prop(sculpt, "use_symmetry_z", text="Z", toggle=True) - layout.column().prop(sculpt, "radial_symmetry", text="Radial") - layout.prop(sculpt, "use_symmetry_feather", text="Feather") + split = layout.split() - layout.label(text="Lock:") + col = split.column() + col.alignment = 'RIGHT' + col.label(text="Lock") - row = layout.row(align=True) + col = split.column() + + row = col.row(align=True) row.prop(sculpt, "lock_x", text="X", toggle=True) row.prop(sculpt, "lock_y", text="Y", toggle=True) row.prop(sculpt, "lock_z", text="Z", toggle=True) - layout.label(text="Tiling:") + split = layout.split() - row = layout.row(align=True) + col = split.column() + col.alignment = 'RIGHT' + col.label(text="Tiling") + + col = split.column() + + row = col.row(align=True) row.prop(sculpt, "tile_x", text="X", toggle=True) row.prop(sculpt, "tile_y", text="Y", toggle=True) row.prop(sculpt, "tile_z", text="Z", toggle=True) + layout.use_property_split = True + + layout.prop(sculpt, "use_symmetry_feather", text="Feather") + layout.column().prop(sculpt, "radial_symmetry", text="Radial") layout.column().prop(sculpt, "tile_offset", text="Tile Offset") +# TODO, move to space_view3d.py class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel): - bl_category = "Options" + bl_context = ".paint_common" # dot on purpose (access from topbar) bl_label = "Appearance" @classmethod @@ -1739,25 +1090,9 @@ class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel): # ********** default tools for weight-paint **************** -class VIEW3D_PT_tools_weightpaint(View3DPanel, Panel): - bl_category = "Tools" - bl_context = "weightpaint" - bl_label = "Weight Tools" - - def draw(self, context): - layout = self.layout - VIEW3D_PT_tools_meshweight.draw_generic(layout) - - col = layout.column() - col.operator("paint.weight_gradient") - props = col.operator("object.data_transfer", text="Transfer Weights") - props.use_reverse_transfer = True - props.data_type = 'VGROUP_WEIGHTS' - - +# TODO, move to space_view3d.py class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel): - bl_category = "Tools" - bl_context = "weightpaint" + bl_context = ".weightpaint" bl_options = {'DEFAULT_CLOSED'} bl_label = "Symmetry" @@ -1768,9 +1103,9 @@ class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel): draw_vpaint_symmetry(layout, wpaint) +# TODO, move to space_view3d.py class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel): - bl_category = "Options" - bl_context = "weightpaint" + bl_context = ".weightpaint" bl_label = "Options" def draw(self, context): @@ -1799,9 +1134,9 @@ class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel): # ********** default tools for vertex-paint **************** +# TODO, move to space_view3d.py class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel): - bl_category = "Options" - bl_context = "vertexpaint" + bl_context = ".vertexpaint" # dot on purpose (access from topbar) bl_label = "Options" def draw(self, context): @@ -1815,9 +1150,9 @@ class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel): self.unified_paint_settings(col, context) +# TODO, move to space_view3d.py class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel): - bl_category = "Tools" - bl_context = "vertexpaint" + bl_context = ".vertexpaint" # dot on purpose (access from topbar) bl_options = {'DEFAULT_CLOSED'} bl_label = "Symmetry" @@ -1831,9 +1166,9 @@ class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel): # ********** default tools for texture-paint **************** +# TODO, move to space_view3d.py class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel): - bl_category = "Tools" - bl_context = "imagepaint" + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "External" bl_options = {'DEFAULT_CLOSED'} @@ -1853,9 +1188,9 @@ class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel): col.operator("paint.project_image", text="Apply Camera Image") +# TODO, move to space_view3d.py class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel): - bl_category = "Tools" - bl_context = "imagepaint" + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Symmetry" bl_options = {'DEFAULT_CLOSED'} @@ -1865,16 +1200,23 @@ class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel): toolsettings = context.tool_settings ipaint = toolsettings.image_paint - col = layout.column(align=True) + split = layout.split() + + col = split.column() + col.alignment = 'RIGHT' + col.label(text="Mirror") + + col = split.column() + row = col.row(align=True) row.prop(ipaint, "use_symmetry_x", text="X", toggle=True) row.prop(ipaint, "use_symmetry_y", text="Y", toggle=True) row.prop(ipaint, "use_symmetry_z", text="Z", toggle=True) +# TODO, move to space_view3d.py class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel): - bl_category = "Options" - bl_context = "imagepaint" + bl_context = ".imagepaint" # dot on purpose (access from topbar) bl_label = "Project Paint" @classmethod @@ -1909,8 +1251,8 @@ class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel): self.unified_paint_settings(layout, context) +# TODO, move to space_view3d.py class VIEW3D_PT_imagepaint_options(View3DPaintPanel): - bl_category = "Options" bl_label = "Options" @classmethod @@ -1929,17 +1271,17 @@ class VIEW3D_MT_tools_projectpaint_stencil(Menu): def draw(self, context): layout = self.layout - for i, tex in enumerate(context.active_object.data.uv_textures): - props = layout.operator("wm.context_set_int", text=tex.name, translate=False) - props.data_path = "active_object.data.uv_texture_stencil_index" + for i, uv_layer in enumerate(context.active_object.data.uv_layers): + props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False) + props.data_path = "active_object.data.uv_layer_stencil_index" props.value = i +# TODO, move to space_view3d.py class VIEW3D_PT_tools_particlemode(View3DPanel, Panel): """Default tools for particle mode""" - bl_context = "particlemode" + bl_context = ".particlemode" bl_label = "Options" - bl_category = "Tools" def draw(self, context): layout = self.layout @@ -2007,9 +1349,295 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel): sub.prop(pe, "fade_frames", slider=True) -# Grease Pencil drawing tools -class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel): +class VIEW3D_PT_tools_normal(View3DPanel, Panel): + bl_category = "" + bl_context = ".mesh_edit" + bl_label = "Normal Tools" + + def draw(self, context): + layout = self.layout + toolsettings = context.tool_settings + + col = layout.column(align=True) + col.label(text="Normal Vector") + col.prop(toolsettings, "normal_vector", text="") + + layout.separator() + layout.label(text="Face Strength") + layout.prop(toolsettings, "face_strength", text="") + + col = layout.column(align=True) + + +# ********** grease pencil object tool panels **************** + +# Grease Pencil drawing brushes +class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Brush" + + @classmethod + def poll(cls, context): + is_3d_view = context.space_data.type == 'VIEW_3D' + if is_3d_view: + if context.gpencil_data is None: + return False + + gpd = context.gpencil_data + return bool(gpd.is_stroke_paint_mode) + else: + return True + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + ts = context.scene.tool_settings + settings = ts.gpencil_paint + + row = layout.row() + col = row.column() + col.template_ID_preview(settings, "brush", new="brush.add_gpencil", rows=3, cols=8) + + col = row.column() + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + sub = col.column(align=True) + sub.operator("gpencil.brush_presets_create", icon='HELP', text="") + + if brush is not None: + # XXX: Items in "sub" currently show up beside the brush selector in a separate column + if gp_settings.gpencil_brush_type == 'ERASE': + sub.prop(gp_settings, "default_eraser", text="") + + # Brush details + if gp_settings.gpencil_brush_type == 'ERASE': + col = layout.column(align=True) + col.prop(brush, "size", text="Radius") + + col.separator() + row = col.row() + row.prop(gp_settings, "eraser_mode", expand=True) + elif gp_settings.gpencil_brush_type == 'FILL': + col = layout.column(align=True) + col.prop(gp_settings, "gpencil_fill_leak", text="Leak Size") + col.prop(brush, "size", text="Thickness") + col.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify") + + col = layout.row(align=True) + col.template_ID(gp_settings, "material") + + row = layout.row(align=True) + row.prop(gp_settings, "gpencil_fill_draw_mode", text="Boundary Draw Mode") + row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID') + + col = layout.column(align=True) + col.enabled = gp_settings.gpencil_fill_draw_mode != "STROKE" + col.prop(gp_settings, "gpencil_fill_hide", text="Hide Transparent Lines") + sub = col.row(align=True) + sub.enabled = gp_settings.gpencil_fill_hide + sub.prop(gp_settings, "gpencil_fill_threshold", text="Threshold") + else: # bgpsettings.gpencil_brush_type == 'DRAW': + row = layout.row(align=True) + row.prop(brush, "size", text="Radius") + row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE') + row = layout.row(align=True) + row.prop(gp_settings, "pen_strength", slider=True) + row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE') + + row = layout.row(align=True) + row.template_ID(gp_settings, "material") + + +# Grease Pencil drawing brushes options +class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Options" + bl_options = {'DEFAULT_CLOSED'} + + def draw_header_preset(self, context): + VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout) + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + if brush is not None: + col = layout.column(align=True) + col.prop(gp_settings, "input_samples") + col.separator() + + col.prop(gp_settings, "active_smooth_factor") + col.separator() + + col.prop(gp_settings, "angle", slider=True) + col.prop(gp_settings, "angle_factor", text="Factor", slider=True) + col.separator() + + +class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option' + bl_label = "Stabilizer" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + return brush is not None and gp_settings.gpencil_brush_type == 'DRAW' + + def draw_header(self, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + self.layout.prop(gp_settings, "use_stabilizer", text="") + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + layout.active = gp_settings.use_stabilizer + + layout.prop(brush, "smooth_stroke_radius", text="Radius", slider=True) + layout.prop(brush, "smooth_stroke_factor", text="Factor", slider=True) + + +class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option' + bl_label = "Post-processing Settings" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + brush = context.active_gpencil_brush + + return brush is not None + + def draw_header(self, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + self.layout.prop(gp_settings, "enable_settings", text="") + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + layout.active = gp_settings.enable_settings + + col = layout.column(align=True) + col.prop(gp_settings, "pen_smooth_factor") + col.prop(gp_settings, "pen_thick_smooth_factor") + + col = layout.column(align=True) + col.prop(gp_settings, "pen_smooth_steps") + col.prop(gp_settings, "pen_thick_smooth_steps") + + col = layout.column(align=True) + col.prop(gp_settings, "pen_subdivision_steps") + col.prop(gp_settings, "random_subdiv", text="Randomness", slider=True) + + +class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option' + bl_label = "Random Settings" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + brush = context.active_gpencil_brush + + return brush is not None + + def draw_header(self, context): + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + self.layout.prop(gp_settings, "enable_random", text="") + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + layout.active = gp_settings.enable_random + + layout.prop(gp_settings, "random_pressure", text="Pressure", slider=True) + layout.prop(gp_settings, "random_strength", text="Strength", slider=True) + layout.prop(gp_settings, "uv_random", text="UV", slider=True) + + row = layout.row(align=True) + row.prop(gp_settings, "pen_jitter", slider=True) + row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE') + + +# Grease Pencil drawingcurves +class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Curves" + bl_options = {'DEFAULT_CLOSED'} + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + brush = context.active_gpencil_brush + gp_settings = brush.gpencil_settings + + # Brush + layout.label("Sensitivity") + layout.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True) + + layout.label("Strength") + layout.template_curve_mapping(gp_settings, "curve_strength", brush=True) + + layout.label("Jitter") + layout.template_curve_mapping(gp_settings, "curve_jitter", brush=True) + + +# Grease Pencil create shapes +class VIEW3D_PT_tools_grease_pencil_shapes(View3DPanel, Panel): bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Shapes" + + @classmethod + def poll(cls, context): + ob = context.active_object + return ob and ob.type == 'GPENCIL' + + @staticmethod + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + col = layout.column(align=True) + col.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE' + col.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX' + col.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE' + + layout.operator("object.gpencil_add", text="Monkey", icon='MONKEY').type = 'MONKEY' # Grease Pencil stroke editing tools @@ -2018,80 +1646,115 @@ class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): # Grease Pencil stroke interpolation tools -class VIEW3D_PT_tools_grease_pencil_interpolate(GreasePencilInterpolatePanel, Panel): +class VIEW3D_PT_tools_grease_pencil_interpolate(Panel): bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Interpolate" + + @classmethod + def poll(cls, context): + if context.gpencil_data is None: + return False + gpd = context.gpencil_data + return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode) -# Grease Pencil stroke sculpting tools -class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): - bl_space_type = 'VIEW_3D' + @staticmethod + def draw(self, context): + layout = self.layout + settings = context.tool_settings.gpencil_interpolate + col = layout.column(align=True) + col.label("Interpolate Strokes") + col.operator("gpencil.interpolate", text="Interpolate") + col.operator("gpencil.interpolate_sequence", text="Sequence") + col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns") -# Grease Pencil drawing brushes -class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel): - bl_space_type = 'VIEW_3D' + col = layout.column(align=True) + col.label(text="Options:") + col.prop(settings, "interpolate_all_layers") + col.prop(settings, "interpolate_selected_only") -# Grease Pencil drawingcurves + col = layout.column(align=True) + col.label(text="Sequence Options:") + col.prop(settings, "type") + if settings.type == 'CUSTOM': + # TODO: Options for loading/saving curve presets? + col.template_curve_mapping(settings, "interpolation_curve", brush=True) + elif settings.type != 'LINEAR': + col.prop(settings, "easing") + + if settings.type == 'BACK': + layout.prop(settings, "back") + elif setting.type == 'ELASTIC': + sub = layout.column(align=True) + sub.prop(settings, "amplitude") + sub.prop(settings, "period") -class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel): - bl_space_type = 'VIEW_3D' +# Grease Pencil stroke sculpting tools +class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, View3DPanel, Panel): + bl_context = ".greasepencil_sculpt" + bl_category = "Tools" + bl_label = "Sculpt Strokes" -# Note: moved here so that it's always in last position in 'Tools' panels! -class VIEW3D_PT_tools_history(View3DPanel, Panel): +# Grease Pencil weight painting tools +class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel): + bl_context = ".greasepencil_weight" bl_category = "Tools" - # No bl_context, we are always available! - bl_label = "History" - bl_options = {'DEFAULT_CLOSED'} + bl_label = "Weight Paint" + @staticmethod def draw(self, context): layout = self.layout - obj = context.object + layout.use_property_split = True + layout.use_property_decorate = False - col = layout.column(align=True) + gpd = context.gpencil_data + settings = context.tool_settings.gpencil_sculpt + tool = settings.tool + brush = settings.brush + + layout.template_icon_view(settings, "weight_tool", show_labels=True) + + col = layout.column() + col.prop(brush, "size", slider=True) row = col.row(align=True) - row.operator("ed.undo") - row.operator("ed.redo") - if obj is None or obj.mode != 'SCULPT': - # Sculpt mode does not generate an undo menu it seems... - col.operator("ed.undo_history") + row.prop(brush, "strength", slider=True) + row.prop(brush, "use_pressure_strength", text="") + + col.prop(brush, "use_falloff") + + +# Grease Pencil Brush Appeareance (one for each mode) +class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilAppearancePanel, View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Appearance" - col = layout.column(align=True) - col.label(text="Repeat:") - col.operator("screen.repeat_last") - col.operator("screen.repeat_history", text="History...") + +class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilAppearancePanel, View3DPanel, Panel): + bl_context = ".greasepencil_sculpt" + bl_label = "Appearance" + + +class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilAppearancePanel, View3DPanel, Panel): + bl_context = ".greasepencil_weight" + bl_label = "Appearance" + + +class VIEW3D_PT_gpencil_brush_presets(PresetMenu): + """Brush settings""" + bl_label = "Brush Presets" + preset_subdir = "gpencil_brush" + preset_operator = "script.execute_preset" + preset_add_operator = "scene.gpencil_brush_preset_add" classes = ( - VIEW3D_PT_tools_transform, - VIEW3D_PT_tools_object, - VIEW3D_PT_tools_add_object, - VIEW3D_PT_tools_relations, - VIEW3D_PT_tools_animation, - VIEW3D_PT_tools_rigid_body, - VIEW3D_PT_tools_transform_mesh, - VIEW3D_PT_tools_meshedit, - VIEW3D_PT_tools_meshweight, - VIEW3D_PT_tools_add_mesh_edit, - VIEW3D_PT_tools_shading, - VIEW3D_PT_tools_uvs, VIEW3D_PT_tools_meshedit_options, - VIEW3D_PT_tools_transform_curve, - VIEW3D_PT_tools_curveedit, - VIEW3D_PT_tools_add_curve_edit, VIEW3D_PT_tools_curveedit_options_stroke, - VIEW3D_PT_tools_transform_surface, - VIEW3D_PT_tools_surfaceedit, - VIEW3D_PT_tools_add_surface_edit, - VIEW3D_PT_tools_textedit, - VIEW3D_PT_tools_armatureedit, - VIEW3D_PT_tools_armatureedit_transform, VIEW3D_PT_tools_armatureedit_options, - VIEW3D_PT_tools_mballedit, - VIEW3D_PT_tools_add_mball_edit, - VIEW3D_PT_tools_latticeedit, - VIEW3D_PT_tools_posemode, VIEW3D_PT_tools_posemode_options, VIEW3D_PT_imapaint_tools_missing, VIEW3D_PT_tools_brush, @@ -2108,7 +1771,6 @@ classes = ( VIEW3D_PT_sculpt_options, VIEW3D_PT_sculpt_symmetry, VIEW3D_PT_tools_brush_appearance, - VIEW3D_PT_tools_weightpaint, VIEW3D_PT_tools_weightpaint_symmetry, VIEW3D_PT_tools_weightpaint_options, VIEW3D_PT_tools_vertexpaint, @@ -2118,13 +1780,22 @@ classes = ( VIEW3D_PT_tools_projectpaint, VIEW3D_MT_tools_projectpaint_stencil, VIEW3D_PT_tools_particlemode, - VIEW3D_PT_tools_grease_pencil_draw, - VIEW3D_PT_tools_grease_pencil_edit, - VIEW3D_PT_tools_grease_pencil_interpolate, - VIEW3D_PT_tools_grease_pencil_sculpt, + + VIEW3D_PT_gpencil_brush_presets, VIEW3D_PT_tools_grease_pencil_brush, + VIEW3D_PT_tools_grease_pencil_brush_option, + VIEW3D_PT_tools_grease_pencil_brush_settings, + VIEW3D_PT_tools_grease_pencil_brush_stabilizer, + VIEW3D_PT_tools_grease_pencil_brush_random, VIEW3D_PT_tools_grease_pencil_brushcurves, - VIEW3D_PT_tools_history, + VIEW3D_PT_tools_grease_pencil_shapes, + VIEW3D_PT_tools_grease_pencil_sculpt, + VIEW3D_PT_tools_grease_pencil_weight_paint, + VIEW3D_PT_tools_grease_pencil_paint_appearance, + VIEW3D_PT_tools_grease_pencil_sculpt_appearance, + VIEW3D_PT_tools_grease_pencil_weight_appearance, + VIEW3D_PT_tools_grease_pencil_interpolate, + VIEW3D_PT_tools_normal, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 4f4190da30b..a70d78c16c6 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -43,18 +43,10 @@ class CompositorNodeCategory(SortedNodeCategory): return (context.space_data.tree_type == 'CompositorNodeTree') -class ShaderNewNodeCategory(SortedNodeCategory): +class ShaderNodeCategory(SortedNodeCategory): @classmethod def poll(cls, context): - return (context.space_data.tree_type == 'ShaderNodeTree' and - context.scene.render.use_shading_nodes) - - -class ShaderOldNodeCategory(SortedNodeCategory): - @classmethod - def poll(cls, context): - return (context.space_data.tree_type == 'ShaderNodeTree' and - not context.scene.render.use_shading_nodes) + return (context.space_data.tree_type == 'ShaderNodeTree') class TextureNodeCategory(SortedNodeCategory): @@ -142,62 +134,39 @@ def object_shader_nodes_poll(context): snode.shader_type == 'OBJECT') +def cycles_shader_nodes_poll(context): + return context.engine == 'CYCLES' + + +def eevee_shader_nodes_poll(context): + return context.engine == 'BLENDER_EEVEE' + + +def eevee_cycles_shader_nodes_poll(context): + return (cycles_shader_nodes_poll(context) or + eevee_shader_nodes_poll(context)) + + +def object_cycles_shader_nodes_poll(context): + return (object_shader_nodes_poll(context) and + cycles_shader_nodes_poll(context)) + + +def object_eevee_shader_nodes_poll(context): + return (object_shader_nodes_poll(context) and + eevee_shader_nodes_poll(context)) + + +def object_eevee_cycles_shader_nodes_poll(context): + return (object_shader_nodes_poll(context) and + eevee_cycles_shader_nodes_poll(context)) + + # All standard node categories currently used in nodes. shader_node_categories = [ - # Shader Nodes - ShaderOldNodeCategory("SH_INPUT", "Input", items=[ - NodeItem("ShaderNodeMaterial"), - NodeItem("ShaderNodeCameraData"), - NodeItem("ShaderNodeFresnel"), - NodeItem("ShaderNodeLayerWeight"), - NodeItem("ShaderNodeLampData"), - NodeItem("ShaderNodeValue"), - NodeItem("ShaderNodeRGB"), - NodeItem("ShaderNodeTexture"), - NodeItem("ShaderNodeGeometry"), - NodeItem("ShaderNodeExtendedMaterial"), - NodeItem("ShaderNodeParticleInfo"), - NodeItem("ShaderNodeObjectInfo"), - NodeItem("NodeGroupInput", poll=group_input_output_item_poll), - ]), - ShaderOldNodeCategory("SH_OUTPUT", "Output", items=[ - NodeItem("ShaderNodeOutput"), - NodeItem("NodeGroupOutput", poll=group_input_output_item_poll), - ]), - ShaderOldNodeCategory("SH_OP_COLOR", "Color", items=[ - NodeItem("ShaderNodeMixRGB"), - NodeItem("ShaderNodeRGBCurve"), - NodeItem("ShaderNodeInvert"), - NodeItem("ShaderNodeHueSaturation"), - NodeItem("ShaderNodeGamma"), - ]), - ShaderOldNodeCategory("SH_OP_VECTOR", "Vector", items=[ - NodeItem("ShaderNodeNormal"), - NodeItem("ShaderNodeMapping"), - NodeItem("ShaderNodeVectorCurve"), - NodeItem("ShaderNodeVectorTransform"), - NodeItem("ShaderNodeNormalMap"), - ]), - ShaderOldNodeCategory("SH_CONVERTOR", "Converter", items=[ - NodeItem("ShaderNodeValToRGB"), - NodeItem("ShaderNodeRGBToBW"), - NodeItem("ShaderNodeMath"), - NodeItem("ShaderNodeVectorMath"), - NodeItem("ShaderNodeSqueeze"), - NodeItem("ShaderNodeSeparateRGB"), - NodeItem("ShaderNodeCombineRGB"), - NodeItem("ShaderNodeSeparateHSV"), - NodeItem("ShaderNodeCombineHSV"), - ]), - ShaderOldNodeCategory("SH_GROUP", "Group", items=node_group_items), - ShaderOldNodeCategory("SH_LAYOUT", "Layout", items=[ - NodeItem("NodeFrame"), - NodeItem("NodeReroute"), - ]), - - # New Shader Nodes (Cycles) - ShaderNewNodeCategory("SH_NEW_INPUT", "Input", items=[ + # Shader Nodes (Cycles and Eevee) + ShaderNodeCategory("SH_NEW_INPUT", "Input", items=[ NodeItem("ShaderNodeTexCoord"), NodeItem("ShaderNodeAttribute"), NodeItem("ShaderNodeLightPath"), @@ -218,37 +187,38 @@ shader_node_categories = [ NodeItem("ShaderNodeUVAlongStroke", poll=line_style_shader_nodes_poll), NodeItem("NodeGroupInput", poll=group_input_output_item_poll), ]), - ShaderNewNodeCategory("SH_NEW_OUTPUT", "Output", items=[ - NodeItem("ShaderNodeOutputMaterial", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeOutputLamp", poll=object_shader_nodes_poll), + ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[ + NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll), NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll), NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll), NodeItem("NodeGroupOutput", poll=group_input_output_item_poll), ]), - ShaderNewNodeCategory("SH_NEW_SHADER", "Shader", items=[ - NodeItem("ShaderNodeMixShader"), - NodeItem("ShaderNodeAddShader"), - NodeItem("ShaderNodeBsdfDiffuse", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfPrincipled", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfGlossy", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfTransparent", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfRefraction", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfGlass", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfTranslucent", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfAnisotropic", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfVelvet", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfToon", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeSubsurfaceScattering", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeEmission", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeBsdfHair", poll=object_shader_nodes_poll), + ShaderNodeCategory("SH_NEW_SHADER", "Shader", items=[ + NodeItem("ShaderNodeMixShader", poll=eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeAddShader", poll=eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfDiffuse", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfPrincipled", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfGlossy", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfTransparent", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfRefraction", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfGlass", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfTranslucent", poll=object_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfAnisotropic", poll=object_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfVelvet", poll=object_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfToon", poll=object_cycles_shader_nodes_poll), + NodeItem("ShaderNodeSubsurfaceScattering", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeEmission", poll=object_eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeBsdfHair", poll=object_cycles_shader_nodes_poll), NodeItem("ShaderNodeBackground", poll=world_shader_nodes_poll), - NodeItem("ShaderNodeHoldout", poll=object_shader_nodes_poll), - NodeItem("ShaderNodeVolumeAbsorption"), - NodeItem("ShaderNodeVolumeScatter"), + NodeItem("ShaderNodeHoldout", poll=object_cycles_shader_nodes_poll), + NodeItem("ShaderNodeVolumeAbsorption", poll=eevee_cycles_shader_nodes_poll), + NodeItem("ShaderNodeVolumeScatter", poll=eevee_cycles_shader_nodes_poll), NodeItem("ShaderNodeVolumePrincipled"), + NodeItem("ShaderNodeEeveeSpecular", poll=object_eevee_shader_nodes_poll), NodeItem("ShaderNodeBsdfHairPrincipled", poll=object_shader_nodes_poll) ]), - ShaderNewNodeCategory("SH_NEW_TEXTURE", "Texture", items=[ + ShaderNodeCategory("SH_NEW_TEXTURE", "Texture", items=[ NodeItem("ShaderNodeTexImage"), NodeItem("ShaderNodeTexEnvironment"), NodeItem("ShaderNodeTexSky"), @@ -263,7 +233,7 @@ shader_node_categories = [ NodeItem("ShaderNodeTexPointDensity"), NodeItem("ShaderNodeTexIES"), ]), - ShaderNewNodeCategory("SH_NEW_OP_COLOR", "Color", items=[ + ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[ NodeItem("ShaderNodeMixRGB"), NodeItem("ShaderNodeRGBCurve"), NodeItem("ShaderNodeInvert"), @@ -272,7 +242,7 @@ shader_node_categories = [ NodeItem("ShaderNodeGamma"), NodeItem("ShaderNodeBrightContrast"), ]), - ShaderNewNodeCategory("SH_NEW_OP_VECTOR", "Vector", items=[ + ShaderNodeCategory("SH_NEW_OP_VECTOR", "Vector", items=[ NodeItem("ShaderNodeMapping"), NodeItem("ShaderNodeBump"), NodeItem("ShaderNodeDisplacement"), @@ -282,10 +252,11 @@ shader_node_categories = [ NodeItem("ShaderNodeVectorCurve"), NodeItem("ShaderNodeVectorTransform"), ]), - ShaderNewNodeCategory("SH_NEW_CONVERTOR", "Converter", items=[ + ShaderNodeCategory("SH_NEW_CONVERTOR", "Converter", items=[ NodeItem("ShaderNodeMath"), NodeItem("ShaderNodeValToRGB"), NodeItem("ShaderNodeRGBToBW"), + NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll), NodeItem("ShaderNodeVectorMath"), NodeItem("ShaderNodeSeparateRGB"), NodeItem("ShaderNodeCombineRGB"), @@ -296,11 +267,11 @@ shader_node_categories = [ NodeItem("ShaderNodeWavelength"), NodeItem("ShaderNodeBlackbody"), ]), - ShaderNewNodeCategory("SH_NEW_SCRIPT", "Script", items=[ + ShaderNodeCategory("SH_NEW_SCRIPT", "Script", items=[ NodeItem("ShaderNodeScript"), ]), - ShaderNewNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items), - ShaderNewNodeCategory("SH_NEW_LAYOUT", "Layout", items=[ + ShaderNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items), + ShaderNodeCategory("SH_NEW_LAYOUT", "Layout", items=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), ]), diff --git a/release/scripts/templates_py/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py index b74c0f8ee25..d26f3d351bf 100644 --- a/release/scripts/templates_py/addon_add_object.py +++ b/release/scripts/templates_py/addon_add_object.py @@ -45,7 +45,7 @@ class OBJECT_OT_add_object(Operator, AddObjectHelper): bl_label = "Add Mesh Object" bl_options = {'REGISTER', 'UNDO'} - scale = FloatVectorProperty( + scale: FloatVectorProperty( name="scale", default=(1.0, 1.0, 1.0), subtype='TRANSLATION', diff --git a/release/scripts/templates_py/background_job.py b/release/scripts/templates_py/background_job.py index 2f444641a51..020dabeb258 100644 --- a/release/scripts/templates_py/background_job.py +++ b/release/scripts/templates_py/background_job.py @@ -42,11 +42,11 @@ def example_function(text, save_path, render_path): scene.camera = cam_ob # set the active camera cam_ob.location = 0.0, 0.0, 10.0 - # Lamp - lamp_data = bpy.data.lamps.new("MyLamp", 'POINT') - lamp_ob = bpy.data.objects.new(name="MyCam", object_data=lamp_data) - scene.objects.link(lamp_ob) - lamp_ob.location = 2.0, 2.0, 5.0 + # Light + light_data = bpy.data.lights.new("MyLight", 'POINT') + light_ob = bpy.data.objects.new(name="MyCam", object_data=light_data) + scene.objects.link(light_ob) + light_ob.location = 2.0, 2.0, 5.0 if save_path: bpy.ops.wm.save_as_mainfile(filepath=save_path) diff --git a/release/scripts/templates_py/batch_export.py b/release/scripts/templates_py/batch_export.py index 0fc888a2d4e..a07491742ec 100644 --- a/release/scripts/templates_py/batch_export.py +++ b/release/scripts/templates_py/batch_export.py @@ -9,19 +9,19 @@ basedir = os.path.dirname(bpy.data.filepath) if not basedir: raise Exception("Blend file is not saved") -scene = bpy.context.scene +view_layer = bpy.context.view_layer -obj_active = scene.objects.active +obj_active = view_layer.objects.active selection = bpy.context.selected_objects bpy.ops.object.select_all(action='DESELECT') for obj in selection: - obj.select = True + obj.select_set(action='SELECT') # some exporters only use the active object - scene.objects.active = obj + view_layer.objects.active = obj name = bpy.path.clean_name(obj.name) fn = os.path.join(basedir, name) @@ -31,12 +31,12 @@ for obj in selection: # Can be used for multiple formats # bpy.ops.export_scene.x3d(filepath=fn + ".x3d", use_selection=True) - obj.select = False + obj.select_set(action='DESELECT') print("written:", fn) -scene.objects.active = obj_active +view_layer.objects.active = obj_active for obj in selection: - obj.select = True + obj.select_set(action='SELECT') diff --git a/release/scripts/templates_py/custom_nodes.py b/release/scripts/templates_py/custom_nodes.py index 23d8ee55e72..7e4e89dafeb 100644 --- a/release/scripts/templates_py/custom_nodes.py +++ b/release/scripts/templates_py/custom_nodes.py @@ -30,10 +30,15 @@ class MyCustomSocket(NodeSocket): ('DOWN', "Down", "Where your feet are"), ('UP', "Up", "Where your head should be"), ('LEFT', "Left", "Not right"), - ('RIGHT', "Right", "Not left") + ('RIGHT', "Right", "Not left"), ) - my_enum_prop = bpy.props.EnumProperty(name="Direction", description="Just an example", items=my_items, default='UP') + my_enum_prop: bpy.props.EnumProperty( + name="Direction", + description="Just an example", + items=my_items, + default='UP', + ) # Optional function for drawing the socket input value def draw(self, context, layout, node, text): @@ -71,8 +76,8 @@ class MyCustomNode(Node, MyCustomTreeNode): # These work just like custom properties in ID data blocks # Extensive information can be found under # http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties - my_string_prop = bpy.props.StringProperty() - my_float_prop = bpy.props.FloatProperty(default=3.1415926) + my_string_prop: bpy.props.StringProperty() + my_float_prop: bpy.props.FloatProperty(default=3.1415926) # === Optional Functions === # Initialization function, called when a new node is created. diff --git a/release/scripts/templates_py/gamelogic.py b/release/scripts/templates_py/gamelogic.py deleted file mode 100644 index e3bb4a7bb78..00000000000 --- a/release/scripts/templates_py/gamelogic.py +++ /dev/null @@ -1,74 +0,0 @@ -# This script must be assigned to a python controller -# where it can access the object that owns it and the sensors/actuators that it connects to. - -import bge - -# support for Vector(), Matrix() types and advanced functions like Matrix.Scale(...) and Matrix.Rotation(...) -# import mathutils - -# for functions like getWindowWidth(), getWindowHeight() -# import Rasterizer - - -def main(): - cont = bge.logic.getCurrentController() - - # The KX_GameObject that owns this controller. - own = cont.owner - - # for scripts that deal with spacial logic - own_pos = own.worldPosition - - # Some example functions, remove to write your own script. - # check for a positive sensor, will run on any object without errors. - print("Logic info for KX_GameObject", own.name) - input = False - - for sens in cont.sensors: - # The sensor can be on another object, we may want to use it - own_sens = sens.owner - print(" sensor:", sens.name, end=" ") - if sens.positive: - print("(true)") - input = True - else: - print("(false)") - - for actu in cont.actuators: - # The actuator can be on another object, we may want to use it - own_actu = actu.owner - print(" actuator:", actu.name) - - # This runs the actuator or turns it off - # note that actuators will continue to run unless explicitly turned off. - if input: - cont.activate(actu) - else: - cont.deactivate(actu) - - # Its also good practice to get sensors and actuators by name - # rather then index so any changes to their order wont break the script. - - # sens_key = cont.sensors["key_sensor"] - # actu_motion = cont.actuators["motion"] - - # Loop through all other objects in the scene - sce = bge.logic.getCurrentScene() - print("Scene Objects:", sce.name) - for ob in sce.objects: - print(" ", ob.name, ob.worldPosition) - - # Example where collision objects are checked for their properties - # adding to our objects "life" property - """ - actu_collide = cont.sensors["collision_sens"] - for ob in actu_collide.hitObjectList: - # Check to see the object has this property - if "life" in ob: - own["life"] += ob["life"] - ob["life"] = 0 - print(own["life"]) - """ - - -main() diff --git a/release/scripts/templates_py/gamelogic_module.py b/release/scripts/templates_py/gamelogic_module.py deleted file mode 100644 index 88c8cf0d75b..00000000000 --- a/release/scripts/templates_py/gamelogic_module.py +++ /dev/null @@ -1,27 +0,0 @@ -# This module can be accessed by a python controller with -# its execution method set to 'Module' -# * Set the module string to "gamelogic_module.main" (without quotes) -# * When renaming the script it MUST have a .py extension -# * External text modules are supported as long as they are at -# the same location as the blendfile or one of its libraries. - -import bge - -# variables defined here will only be set once when the -# module is first imported. Set object specific vars -# inside the function if you intend to use the module -# with multiple objects. - - -def main(cont): - own = cont.owner - - sens = cont.sensors['mySensor'] - actu = cont.actuators['myActuator'] - - if sens.positive: - cont.activate(actu) - else: - cont.deactivate(actu) - -# dont call main(bge.logic.getCurrentController()), the py controller will diff --git a/release/scripts/templates_py/gamelogic_simple.py b/release/scripts/templates_py/gamelogic_simple.py deleted file mode 100644 index 31cb1885717..00000000000 --- a/release/scripts/templates_py/gamelogic_simple.py +++ /dev/null @@ -1,18 +0,0 @@ -import bge - - -def main(): - - cont = bge.logic.getCurrentController() - own = cont.owner - - sens = cont.sensors['mySensor'] - actu = cont.actuators['myActuator'] - - if sens.positive: - cont.activate(actu) - else: - cont.deactivate(actu) - - -main() diff --git a/release/scripts/templates_py/gizmo_custom_geometry.py b/release/scripts/templates_py/gizmo_custom_geometry.py new file mode 100644 index 00000000000..8125498fa85 --- /dev/null +++ b/release/scripts/templates_py/gizmo_custom_geometry.py @@ -0,0 +1,158 @@ +# Example of a custom widget that defines it's own geometry. +# +# Usage: Select a light in the 3D view and drag the arrow at it's rear +# to change it's energy value. +# +import bpy +from bpy.types import ( + Gizmo, + GizmoGroup, +) + +# Coordinates (each one is a triangle). +custom_shape_verts = ( + (3.0, 1.0, -1.0), (2.0, 2.0, -1.0), (3.0, 3.0, -1.0), + (1.0, 3.0, 1.0), (3.0, 3.0, -1.0), (1.0, 3.0, -1.0), + (3.0, 3.0, 1.0), (3.0, 1.0, -1.0), (3.0, 3.0, -1.0), + (2.0, 0.0, 1.0), (3.0, 1.0, -1.0), (3.0, 1.0, 1.0), + (2.0, 0.0, -1.0), (2.0, 2.0, 1.0), (2.0, 2.0, -1.0), + (2.0, 2.0, -1.0), (0.0, 2.0, 1.0), (0.0, 2.0, -1.0), + (1.0, 3.0, 1.0), (2.0, 2.0, 1.0), (3.0, 3.0, 1.0), + (0.0, 2.0, -1.0), (1.0, 3.0, 1.0), (1.0, 3.0, -1.0), + (2.0, 2.0, 1.0), (3.0, 1.0, 1.0), (3.0, 3.0, 1.0), + (2.0, 2.0, -1.0), (1.0, 3.0, -1.0), (3.0, 3.0, -1.0), + (-3.0, -1.0, -1.0), (-2.0, -2.0, -1.0), (-3.0, -3.0, -1.0), + (-1.0, -3.0, 1.0), (-3.0, -3.0, -1.0), (-1.0, -3.0, -1.0), + (-3.0, -3.0, 1.0), (-3.0, -1.0, -1.0), (-3.0, -3.0, -1.0), + (-2.0, 0.0, 1.0), (-3.0, -1.0, -1.0), (-3.0, -1.0, 1.0), + (-2.0, 0.0, -1.0), (-2.0, -2.0, 1.0), (-2.0, -2.0, -1.0), + (-2.0, -2.0, -1.0), (0.0, -2.0, 1.0), (0.0, -2.0, -1.0), + (-1.0, -3.0, 1.0), (-2.0, -2.0, 1.0), (-3.0, -3.0, 1.0), + (0.0, -2.0, -1.0), (-1.0, -3.0, 1.0), (-1.0, -3.0, -1.0), + (-2.0, -2.0, 1.0), (-3.0, -1.0, 1.0), (-3.0, -3.0, 1.0), + (-2.0, -2.0, -1.0), (-1.0, -3.0, -1.0), (-3.0, -3.0, -1.0), + (1.0, -1.0, 0.0), (-1.0, -1.0, 0.0), (0.0, 0.0, -5.0), + (-1.0, -1.0, 0.0), (1.0, -1.0, 0.0), (0.0, 0.0, 5.0), + (1.0, -1.0, 0.0), (1.0, 1.0, 0.0), (0.0, 0.0, 5.0), + (1.0, 1.0, 0.0), (-1.0, 1.0, 0.0), (0.0, 0.0, 5.0), + (-1.0, 1.0, 0.0), (-1.0, -1.0, 0.0), (0.0, 0.0, 5.0), + (-1.0, -1.0, 0.0), (-1.0, 1.0, 0.0), (0.0, 0.0, -5.0), + (-1.0, 1.0, 0.0), (1.0, 1.0, 0.0), (0.0, 0.0, -5.0), + (1.0, 1.0, 0.0), (1.0, -1.0, 0.0), (0.0, 0.0, -5.0), + (3.0, 1.0, -1.0), (2.0, 0.0, -1.0), (2.0, 2.0, -1.0), + (1.0, 3.0, 1.0), (3.0, 3.0, 1.0), (3.0, 3.0, -1.0), + (3.0, 3.0, 1.0), (3.0, 1.0, 1.0), (3.0, 1.0, -1.0), + (2.0, 0.0, 1.0), (2.0, 0.0, -1.0), (3.0, 1.0, -1.0), + (2.0, 0.0, -1.0), (2.0, 0.0, 1.0), (2.0, 2.0, 1.0), + (2.0, 2.0, -1.0), (2.0, 2.0, 1.0), (0.0, 2.0, 1.0), + (1.0, 3.0, 1.0), (0.0, 2.0, 1.0), (2.0, 2.0, 1.0), + (0.0, 2.0, -1.0), (0.0, 2.0, 1.0), (1.0, 3.0, 1.0), + (2.0, 2.0, 1.0), (2.0, 0.0, 1.0), (3.0, 1.0, 1.0), + (2.0, 2.0, -1.0), (0.0, 2.0, -1.0), (1.0, 3.0, -1.0), + (-3.0, -1.0, -1.0), (-2.0, 0.0, -1.0), (-2.0, -2.0, -1.0), + (-1.0, -3.0, 1.0), (-3.0, -3.0, 1.0), (-3.0, -3.0, -1.0), + (-3.0, -3.0, 1.0), (-3.0, -1.0, 1.0), (-3.0, -1.0, -1.0), + (-2.0, 0.0, 1.0), (-2.0, 0.0, -1.0), (-3.0, -1.0, -1.0), + (-2.0, 0.0, -1.0), (-2.0, 0.0, 1.0), (-2.0, -2.0, 1.0), + (-2.0, -2.0, -1.0), (-2.0, -2.0, 1.0), (0.0, -2.0, 1.0), + (-1.0, -3.0, 1.0), (0.0, -2.0, 1.0), (-2.0, -2.0, 1.0), + (0.0, -2.0, -1.0), (0.0, -2.0, 1.0), (-1.0, -3.0, 1.0), + (-2.0, -2.0, 1.0), (-2.0, 0.0, 1.0), (-3.0, -1.0, 1.0), + (-2.0, -2.0, -1.0), (0.0, -2.0, -1.0), (-1.0, -3.0, -1.0), +) + + +class MyCustomShapeWidget(Gizmo): + bl_idname = "VIEW3D_GT_auto_facemap" + bl_target_properties = ( + {"id": "offset", "type": 'FLOAT', "array_length": 1}, + ) + + __slots__ = ( + "custom_shape", + "init_mouse_y", + "init_value", + ) + + def _update_offset_matrix(self): + # offset behind the light + self.matrix_offset.col[3][2] = self.target_get_value("offset") / -10.0 + + def draw(self, context): + self._update_offset_matrix() + self.draw_custom_shape(self.custom_shape) + + def draw_select(self, context, select_id): + self._update_offset_matrix() + self.draw_custom_shape(self.custom_shape, select_id=select_id) + + def setup(self): + if not hasattr(self, "custom_shape"): + self.custom_shape = self.new_custom_shape('TRIS', custom_shape_verts) + + def invoke(self, context, event): + self.init_mouse_y = event.mouse_y + self.init_value = self.target_get_value("offset") + return {'RUNNING_MODAL'} + + def exit(self, context, cancel): + context.area.header_text_set() + if cancel: + self.target_set_value("offset", self.init_value) + + def modal(self, context, event, tweak): + delta = (event.mouse_y - self.init_mouse_y) / 10.0 + if 'SNAP' in tweak: + delta = round(delta) + if 'PRECISE' in tweak: + delta /= 10.0 + value = self.init_value + delta + self.target_set_value("offset", value) + context.area.header_text_set("My Gizmo: %.4f" % value) + return {'RUNNING_MODAL'} + + +class MyCustomShapeWidgetGroup(GizmoGroup): + bl_idname = "OBJECT_GGT_light_test" + bl_label = "Test Light Widget" + bl_space_type = 'VIEW_3D' + bl_region_type = 'WINDOW' + bl_options = {'3D', 'PERSISTENT'} + + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'LIGHT') + + def setup(self, context): + # Assign the 'offset' target property to the light energy. + ob = context.object + mpr = self.gizmos.new(MyCustomShapeWidget.bl_idname) + mpr.target_set_prop("offset", ob.data, "energy") + mpr.matrix_basis = ob.matrix_world.normalized() + + mpr.color = 1.0, 0.5, 1.0 + mpr.alpha = 0.5 + + mpr.color_highlight = 1.0, 1.0, 1.0 + mpr.alpha_highlight = 0.5 + + # units are large, so shrink to something more reasonable. + mpr.scale_basis = 0.1 + mpr.use_draw_modal = True + + self.energy_widget = mpr + + def refresh(self, context): + ob = context.object + mpr = self.energy_widget + mpr.matrix_basis = ob.matrix_world.normalized() + + +classes = ( + MyCustomShapeWidget, + MyCustomShapeWidgetGroup, +) + +for cls in classes: + bpy.utils.register_class(cls) diff --git a/release/scripts/templates_py/gizmo_operator.py b/release/scripts/templates_py/gizmo_operator.py new file mode 100644 index 00000000000..bdc1bc9893c --- /dev/null +++ b/release/scripts/templates_py/gizmo_operator.py @@ -0,0 +1,234 @@ +# Example of an operator which uses gizmos to control its properties. +# +# Usage: Run this script, then in mesh edit-mode press Spacebar +# to activate the operator "Select Side of Plane" +# The gizmos can then be used to adjust the plane in the 3D view. +# +import bpy +import bmesh + +from bpy.types import ( + Operator, + GizmoGroup, +) + +from bpy.props import ( + FloatVectorProperty, +) + + +def main(context, plane_co, plane_no): + obj = context.active_object + matrix = obj.matrix_world.copy() + me = obj.data + bm = bmesh.from_edit_mesh(me) + + plane_dot = plane_no.dot(plane_co) + + for v in bm.verts: + co = matrix * v.co + v.select = (plane_no.dot(co) > plane_dot) + bm.select_flush_mode() + + bmesh.update_edit_mesh(me) + + +class SelectSideOfPlane(Operator): + """UV Operator description""" + bl_idname = "mesh.select_side_of_plane" + bl_label = "Select Side of Plane" + bl_options = {'REGISTER', 'UNDO'} + + plane_co: FloatVectorProperty( + size=3, + default=(0, 0, 0), + ) + plane_no: FloatVectorProperty( + size=3, + default=(0, 0, 1), + ) + + @classmethod + def poll(cls, context): + return (context.mode == 'EDIT_MESH') + + def invoke(self, context, event): + + if not self.properties.is_property_set("plane_co"): + self.plane_co = context.scene.cursor_location + + if not self.properties.is_property_set("plane_no"): + if context.space_data.type == 'VIEW_3D': + rv3d = context.space_data.region_3d + view_inv = rv3d.view_matrix.to_3x3() + # view y axis + self.plane_no = view_inv[1].normalized() + + self.execute(context) + + if context.space_data.type == 'VIEW_3D': + wm = context.window_manager + wm.gizmo_group_type_add(SelectSideOfPlaneGizmoGroup.bl_idname) + + return {'FINISHED'} + + def execute(self, context): + from mathutils import Vector + main(context, Vector(self.plane_co), Vector(self.plane_no)) + return {'FINISHED'} + + +# Gizmos for plane_co, plane_no +class SelectSideOfPlaneGizmoGroup(GizmoGroup): + bl_idname = "MESH_GGT_select_side_of_plane" + bl_label = "Side of Plane Gizmo" + bl_space_type = 'VIEW_3D' + bl_region_type = 'WINDOW' + bl_options = {'3D'} + + # Helper functions + @staticmethod + def my_target_operator(context): + wm = context.window_manager + op = wm.operators[-1] if wm.operators else None + if isinstance(op, SelectSideOfPlane): + return op + return None + + @staticmethod + def my_view_orientation(context): + rv3d = context.space_data.region_3d + view_inv = rv3d.view_matrix.to_3x3() + return view_inv.normalized() + + @classmethod + def poll(cls, context): + op = cls.my_target_operator(context) + if op is None: + wm = context.window_manager + wm.gizmo_group_type_remove(SelectSideOfPlaneGizmoGroup.bl_idname) + return False + return True + + def setup(self, context): + from mathutils import Matrix, Vector + + # ---- + # Grab + + def grab_get_cb(): + op = SelectSideOfPlaneGizmoGroup.my_target_operator(context) + return op.plane_co + + def grab_set_cb(value): + op = SelectSideOfPlaneGizmoGroup.my_target_operator(context) + op.plane_co = value + # XXX, this may change! + op.execute(context) + + mpr = self.gizmos.new("GIZMO_GT_grab_3d") + mpr.target_set_handler("offset", get=grab_get_cb, set=grab_set_cb) + + mpr.use_draw_value = True + + mpr.color = 0.8, 0.8, 0.8 + mpr.alpha = 0.5 + + mpr.color_highlight = 1.0, 1.0, 1.0 + mpr.alpha_highlight = 1.0 + + mpr.scale_basis = 0.2 + + self.widget_grab = mpr + + # ---- + # Dial + + def direction_get_cb(): + op = SelectSideOfPlaneGizmoGroup.my_target_operator(context) + + no_a = self.widget_dial.matrix_basis.col[1].xyz + no_b = Vector(op.plane_no) + + no_a = (no_a * self.view_inv).xy.normalized() + no_b = (no_b * self.view_inv).xy.normalized() + return no_a.angle_signed(no_b) + + def direction_set_cb(value): + op = SelectSideOfPlaneGizmoGroup.my_target_operator(context) + matrix_rotate = Matrix.Rotation(-value, 3, self.rotate_axis) + no = matrix_rotate * self.widget_dial.matrix_basis.col[1].xyz + op.plane_no = no + op.execute(context) + + mpr = self.gizmos.new("GIZMO_GT_dial_3d") + mpr.target_set_handler("offset", get=direction_get_cb, set=direction_set_cb) + mpr.draw_options = {'ANGLE_START_Y'} + + mpr.use_draw_value = True + + mpr.color = 0.8, 0.8, 0.8 + mpr.alpha = 0.5 + + mpr.color_highlight = 1.0, 1.0, 1.0 + mpr.alpha_highlight = 1.0 + + self.widget_dial = mpr + + def draw_prepare(self, context): + from mathutils import Vector + + view_inv = self.my_view_orientation(context) + + self.view_inv = view_inv + self.rotate_axis = view_inv[2].xyz + self.rotate_up = view_inv[1].xyz + + op = self.my_target_operator(context) + + co = Vector(op.plane_co) + no = Vector(op.plane_no).normalized() + + # Grab + no_z = no + no_y = no_z.orthogonal() + no_x = no_z.cross(no_y) + + matrix = self.widget_grab.matrix_basis + matrix.identity() + matrix.col[0].xyz = no_x + matrix.col[1].xyz = no_y + matrix.col[2].xyz = no_z + matrix.col[3].xyz = co + + # Dial + no_z = self.rotate_axis + no_y = (no - (no.project(no_z))).normalized() + no_x = self.rotate_axis.cross(no_y) + + matrix = self.widget_dial.matrix_basis + matrix.identity() + matrix.col[0].xyz = no_x + matrix.col[1].xyz = no_y + matrix.col[2].xyz = no_z + matrix.col[3].xyz = co + + +classes = ( + SelectSideOfPlane, + SelectSideOfPlaneGizmoGroup, +) + + +def register(): + for cls in classes: + bpy.utils.register_class(cls) + + +def unregister(): + for cls in reversed(classes): + bpy.utils.unregister_class(cls) + + +if __name__ == "__main__": + register() diff --git a/release/scripts/templates_py/gizmo_operator_target.py b/release/scripts/templates_py/gizmo_operator_target.py new file mode 100644 index 00000000000..606aa6749d0 --- /dev/null +++ b/release/scripts/templates_py/gizmo_operator_target.py @@ -0,0 +1,50 @@ +# Example of a gizmo that activates an operator +# using the predefined dial gizmo to change the camera roll. +# +# Usage: Run this script and select a camera in the 3D view. +# +import bpy +from bpy.types import ( + GizmoGroup, +) + + +class MyCameraWidgetGroup(GizmoGroup): + bl_idname = "OBJECT_GGT_test_camera" + bl_label = "Object Camera Test Widget" + bl_space_type = 'VIEW_3D' + bl_region_type = 'WINDOW' + bl_options = {'3D', 'PERSISTENT'} + + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'CAMERA') + + def setup(self, context): + # Run an operator using the dial gizmo + ob = context.object + mpr = self.gizmos.new("GIZMO_GT_dial_3d") + props = mpr.target_set_operator("transform.rotate") + props.constraint_axis = False, False, True + props.constraint_orientation = 'LOCAL' + props.release_confirm = True + + mpr.matrix_basis = ob.matrix_world.normalized() + mpr.line_width = 3 + + mpr.color = 0.8, 0.8, 0.8 + mpr.alpha = 0.5 + + mpr.color_highlight = 1.0, 1.0, 1.0 + mpr.alpha_highlight = 1.0 + + self.roll_widget = mpr + + def refresh(self, context): + ob = context.object + mpr = self.roll_widget + mpr.matrix_basis = ob.matrix_world.normalized() + + +bpy.utils.register_class(MyCameraWidgetGroup) diff --git a/release/scripts/templates_py/gizmo_simple.py b/release/scripts/templates_py/gizmo_simple.py new file mode 100644 index 00000000000..396378da04c --- /dev/null +++ b/release/scripts/templates_py/gizmo_simple.py @@ -0,0 +1,47 @@ +# Example of a group that edits a single property +# using the predefined gizmo arrow. +# +# Usage: Select a light in the 3D view and drag the arrow at it's rear +# to change it's energy value. +# +import bpy +from bpy.types import ( + GizmoGroup, +) + + +class MyLightWidgetGroup(GizmoGroup): + bl_idname = "OBJECT_GGT_light_test" + bl_label = "Test Light Widget" + bl_space_type = 'VIEW_3D' + bl_region_type = 'WINDOW' + bl_options = {'3D', 'PERSISTENT'} + + @classmethod + def poll(cls, context): + ob = context.object + return (ob and ob.type == 'LIGHT') + + def setup(self, context): + # Arrow gizmo has one 'offset' property we can assign to the light energy. + ob = context.object + mpr = self.gizmos.new("GIZMO_GT_arrow_3d") + mpr.target_set_prop("offset", ob.data, "energy") + mpr.matrix_basis = ob.matrix_world.normalized() + mpr.draw_style = 'BOX' + + mpr.color = 1.0, 0.5, 0.0 + mpr.alpha = 0.5 + + mpr.color_highlight = 1.0, 0.5, 1.0 + mpr.alpha_highlight = 0.5 + + self.energy_widget = mpr + + def refresh(self, context): + ob = context.object + mpr = self.energy_widget + mpr.matrix_basis = ob.matrix_world.normalized() + + +bpy.utils.register_class(MyLightWidgetGroup) diff --git a/release/scripts/templates_py/operator_file_export.py b/release/scripts/templates_py/operator_file_export.py index 8a1eb4ae54c..4ea817d3507 100644 --- a/release/scripts/templates_py/operator_file_export.py +++ b/release/scripts/templates_py/operator_file_export.py @@ -25,7 +25,7 @@ class ExportSomeData(Operator, ExportHelper): # ExportHelper mixin class uses this filename_ext = ".txt" - filter_glob = StringProperty( + filter_glob: StringProperty( default="*.txt", options={'HIDDEN'}, maxlen=255, # Max internal buffer length, longer would be clamped. @@ -33,13 +33,13 @@ class ExportSomeData(Operator, ExportHelper): # List of operator properties, the attributes will be assigned # to the class instance from the operator settings before calling. - use_setting = BoolProperty( + use_setting: BoolProperty( name="Example Boolean", description="Example Tooltip", default=True, ) - type = EnumProperty( + type: EnumProperty( name="Example Enum", description="Choose between two items", items=( diff --git a/release/scripts/templates_py/operator_file_import.py b/release/scripts/templates_py/operator_file_import.py index 9856b6a9040..b932b008c49 100644 --- a/release/scripts/templates_py/operator_file_import.py +++ b/release/scripts/templates_py/operator_file_import.py @@ -28,7 +28,7 @@ class ImportSomeData(Operator, ImportHelper): # ImportHelper mixin class uses this filename_ext = ".txt" - filter_glob = StringProperty( + filter_glob: StringProperty( default="*.txt", options={'HIDDEN'}, maxlen=255, # Max internal buffer length, longer would be clamped. @@ -36,13 +36,13 @@ class ImportSomeData(Operator, ImportHelper): # List of operator properties, the attributes will be assigned # to the class instance from the operator settings before calling. - use_setting = BoolProperty( + use_setting: BoolProperty( name="Example Boolean", description="Example Tooltip", default=True, ) - type = EnumProperty( + type: EnumProperty( name="Example Enum", description="Choose between two items", items=( diff --git a/release/scripts/templates_py/operator_mesh_add.py b/release/scripts/templates_py/operator_mesh_add.py index 407956a0fda..6b39ef7bbba 100644 --- a/release/scripts/templates_py/operator_mesh_add.py +++ b/release/scripts/templates_py/operator_mesh_add.py @@ -49,25 +49,25 @@ class AddBox(bpy.types.Operator): bl_label = "Add Box" bl_options = {'REGISTER', 'UNDO'} - width = FloatProperty( + width: FloatProperty( name="Width", description="Box Width", min=0.01, max=100.0, default=1.0, ) - height = FloatProperty( + height: FloatProperty( name="Height", description="Box Height", min=0.01, max=100.0, default=1.0, ) - depth = FloatProperty( + depth: FloatProperty( name="Depth", description="Box Depth", min=0.01, max=100.0, default=1.0, ) - layers = BoolVectorProperty( + layers: BoolVectorProperty( name="Layers", description="Object Layers", size=20, @@ -75,15 +75,15 @@ class AddBox(bpy.types.Operator): ) # generic transform props - view_align = BoolProperty( + view_align: BoolProperty( name="Align to View", default=False, ) - location = FloatVectorProperty( + location: FloatVectorProperty( name="Location", subtype='TRANSLATION', ) - rotation = FloatVectorProperty( + rotation: FloatVectorProperty( name="Rotation", subtype='EULER', ) diff --git a/release/scripts/templates_py/operator_modal.py b/release/scripts/templates_py/operator_modal.py index 88e5ee80590..c242e3b67b9 100644 --- a/release/scripts/templates_py/operator_modal.py +++ b/release/scripts/templates_py/operator_modal.py @@ -7,8 +7,8 @@ class ModalOperator(bpy.types.Operator): bl_idname = "object.modal_operator" bl_label = "Simple Modal Operator" - first_mouse_x = IntProperty() - first_value = FloatProperty() + first_mouse_x: IntProperty() + first_value: FloatProperty() def modal(self, context, event): if event.type == 'MOUSEMOVE': diff --git a/release/scripts/templates_py/operator_modal_view3d.py b/release/scripts/templates_py/operator_modal_view3d.py index 65bab3489b4..9d371446829 100644 --- a/release/scripts/templates_py/operator_modal_view3d.py +++ b/release/scripts/templates_py/operator_modal_view3d.py @@ -8,7 +8,7 @@ class ViewOperator(bpy.types.Operator): bl_idname = "view3d.modal_operator" bl_label = "Simple View Operator" - offset = FloatVectorProperty( + offset: FloatVectorProperty( name="Offset", size=3, ) diff --git a/release/scripts/templates_py/operator_modal_view3d_raycast.py b/release/scripts/templates_py/operator_modal_view3d_raycast.py index c4d661b4c1f..613501143f7 100644 --- a/release/scripts/templates_py/operator_modal_view3d_raycast.py +++ b/release/scripts/templates_py/operator_modal_view3d_raycast.py @@ -67,8 +67,8 @@ def main(context, event): # now we have the object under the mouse cursor, # we could do lots of stuff but for the example just select. if best_obj is not None: - best_obj.select = True - context.scene.objects.active = best_obj + best_obj.select_set(action='SELECT') + context.view_layer.objects.active = best_obj class ViewOperatorRayCast(bpy.types.Operator): diff --git a/release/scripts/templates_py/ui_list.py b/release/scripts/templates_py/ui_list.py index 92e1b29d2ae..f6b82356a78 100644 --- a/release/scripts/templates_py/ui_list.py +++ b/release/scripts/templates_py/ui_list.py @@ -7,8 +7,10 @@ class MESH_UL_mylist(bpy.types.UIList): # E.g. VGROUP_EMPTY = 1 << 0 # Custom properties, saved with .blend file. E.g. - # use_filter_empty = bpy.props.BoolProperty(name="Filter Empty", default=False, options=set(), - # description="Whether to filter empty vertex groups") + # use_filter_empty: bpy.props.BoolProperty( + # name="Filter Empty", default=False, options=set(), + # description="Whether to filter empty vertex groups", + # ) # Called for each drawn item. def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag): diff --git a/release/scripts/templates_py/ui_list_simple.py b/release/scripts/templates_py/ui_list_simple.py index e911a0dd236..79c14c17c7e 100644 --- a/release/scripts/templates_py/ui_list_simple.py +++ b/release/scripts/templates_py/ui_list_simple.py @@ -28,18 +28,6 @@ class MATERIAL_UL_matslots_example(bpy.types.UIList): layout.prop(ma, "name", text="", emboss=False, icon_value=icon) else: layout.label(text="", translate=False, icon_value=icon) - # And now we can add other UI stuff... - # Here, we add nodes info if this material uses (old!) shading nodes. - if ma and not context.scene.render.use_shading_nodes: - manode = ma.active_node_material - if manode: - # The static method UILayout.icon returns the integer value of the icon ID "computed" for the given - # RNA object. - layout.label(text="Node %s" % manode.name, translate=False, icon_value=layout.icon(manode)) - elif ma.use_nodes: - layout.label(text="Node <none>", translate=False) - else: - layout.label(text="") # 'GRID' layout type should be as compact as possible (typically a single icon!). elif self.layout_type in {'GRID'}: layout.alignment = 'CENTER' |