diff options
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/startup/bl_operators/__init__.py | 3 | ||||
-rw-r--r-- | release/scripts/startup/bl_operators/anim.py | 127 | ||||
-rw-r--r-- | release/scripts/startup/bl_operators/console.py | 106 | ||||
-rw-r--r-- | release/scripts/startup/bl_operators/view3d.py | 77 | ||||
-rw-r--r-- | release/scripts/startup/bl_operators/wm.py | 704 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/properties_scene.py | 109 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_console.py | 85 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_info.py | 32 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_userpref.py | 289 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_userpref_keymap.py | 397 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 57 |
11 files changed, 1024 insertions, 962 deletions
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py index d5f7a63366a..918e9153b73 100644 --- a/release/scripts/startup/bl_operators/__init__.py +++ b/release/scripts/startup/bl_operators/__init__.py @@ -24,7 +24,9 @@ if "bpy" in locals(): _reload(val) _modules = ( "add_mesh_torus", + "anim", "animsys_update", + "console", "image", "mesh", "nla", @@ -39,6 +41,7 @@ _modules = ( "uvcalc_lightmap", "uvcalc_smart_project", "vertexpaint_dirt", + "view3d", "wm", ) __import__(name=__name__, fromlist=_modules) diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py new file mode 100644 index 00000000000..4e3c2874ffa --- /dev/null +++ b/release/scripts/startup/bl_operators/anim.py @@ -0,0 +1,127 @@ +# ##### 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> + +import bpy +from bpy.types import Operator + + +class ANIM_OT_keying_set_export(Operator): + "Export Keying Set to a python script" + bl_idname = "anim.keying_set_export" + bl_label = "Export Keying Set..." + + filepath = bpy.props.StringProperty(name="File Path", description="Filepath to write file to") + filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'}) + filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'}) + filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'}) + + def execute(self, context): + if not self.filepath: + raise Exception("Filepath not set") + + f = open(self.filepath, "w") + if not f: + raise Exception("Could not open file") + + scene = context.scene + ks = scene.keying_sets.active + + f.write("# Keying Set: %s\n" % ks.name) + + f.write("import bpy\n\n") + f.write("scene= bpy.data.scenes[0]\n\n") # XXX, why not use the current scene? + + # Add KeyingSet and set general settings + f.write("# Keying Set Level declarations\n") + f.write("ks= scene.keying_sets.new(name=\"%s\")\n" % ks.name) + + if not ks.is_path_absolute: + f.write("ks.is_path_absolute = False\n") + f.write("\n") + + f.write("ks.bl_options = %r\n" % ks.bl_options) + f.write("\n") + + # generate and write set of lookups for id's used in paths + id_to_paths_cache = {} # cache for syncing ID-blocks to bpy paths + shorthands + + for ksp in ks.paths: + if ksp.id is None: + continue + if ksp.id in id_to_paths_cache: + continue + + # - idtype_list is used to get the list of id-datablocks from bpy.data.* + # since this info isn't available elsewhere + # - id.bl_rna.name gives a name suitable for UI, + # with a capitalised first letter, but we need + # the plural form that's all lower case + idtype_list = ksp.id.bl_rna.name.lower() + "s" + id_bpy_path = "bpy.data.%s[\"%s\"]" % (idtype_list, ksp.id.name) + + # shorthand ID for the ID-block (as used in the script) + short_id = "id_%d" % len(id_to_paths_cache) + + # store this in the cache now + id_to_paths_cache[ksp.id] = [short_id, id_bpy_path] + + f.write("# ID's that are commonly used\n") + for id_pair in id_to_paths_cache.values(): + f.write("%s = %s\n" % (id_pair[0], id_pair[1])) + f.write("\n") + + # write paths + f.write("# Path Definitions\n") + for ksp in ks.paths: + f.write("ksp = ks.paths.add(") + + # id-block + data_path + if ksp.id: + # find the relevant shorthand from the cache + id_bpy_path = id_to_paths_cache[ksp.id][0] + else: + id_bpy_path = "None" # XXX... + f.write("%s, '%s'" % (id_bpy_path, ksp.data_path)) + + # array index settings (if applicable) + if ksp.use_entire_array: + f.write(", index=-1") + else: + f.write(", index=%d" % ksp.array_index) + + # grouping settings (if applicable) + # NOTE: the current default is KEYINGSET, but if this changes, change this code too + if ksp.group_method == 'NAMED': + f.write(", group_method='%s', group_name=\"%s\"" % (ksp.group_method, ksp.group)) + elif ksp.group_method != 'KEYINGSET': + f.write(", group_method='%s'" % ksp.group_method) + + # finish off + f.write(")\n") + + f.write("\n") + f.close() + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'}
\ No newline at end of file diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py new file mode 100644 index 00000000000..78a5abbc741 --- /dev/null +++ b/release/scripts/startup/bl_operators/console.py @@ -0,0 +1,106 @@ +# ##### 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> + +import bpy +from bpy.types import Operator +from bpy.props import StringProperty + + +class ConsoleExec(Operator): + '''Execute the current console line as a python expression''' + bl_idname = "console.execute" + bl_label = "Console Execute" + + def execute(self, context): + sc = context.space_data + + module = __import__("console_" + sc.language) + execute = getattr(module, "execute", None) + + if execute: + return execute(context) + else: + print("Error: bpy.ops.console.execute_" + sc.language + " - not found") + return {'FINISHED'} + + +class ConsoleAutocomplete(Operator): + '''Evaluate the namespace up until the cursor and give a list of options or complete the name if there is only one''' + bl_idname = "console.autocomplete" + bl_label = "Console Autocomplete" + + def execute(self, context): + sc = context.space_data + module = __import__("console_" + sc.language) + autocomplete = getattr(module, "autocomplete", None) + + if autocomplete: + return autocomplete(context) + else: + print("Error: bpy.ops.console.autocomplete_" + sc.language + " - not found") + return {'FINISHED'} + + +class ConsoleBanner(Operator): + '''Print a message whem the terminal initializes''' + bl_idname = "console.banner" + bl_label = "Console Banner" + + def execute(self, context): + sc = context.space_data + + # default to python + if not sc.language: + sc.language = 'python' + + module = __import__("console_" + sc.language) + banner = getattr(module, "banner", None) + + if banner: + return banner(context) + else: + print("Error: bpy.ops.console.banner_" + sc.language + " - not found") + return {'FINISHED'} + + +class ConsoleLanguage(Operator): + '''Set the current language for this console''' + bl_idname = "console.language" + bl_label = "Console Language" + + language = StringProperty( + name="Language", + maxlen=32, + ) + + def execute(self, context): + sc = context.space_data + + # defailt to python + sc.language = self.language + + bpy.ops.console.banner() + + # insert a new blank line + bpy.ops.console.history_append(text="", current_character=0, + remove_duplicates=True) + + return {'FINISHED'} +
\ No newline at end of file diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py new file mode 100644 index 00000000000..d9a64ec807a --- /dev/null +++ b/release/scripts/startup/bl_operators/view3d.py @@ -0,0 +1,77 @@ +# ##### 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> + +import bpy +from bpy.types import Operator + + +class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator): + "Extrude individual elements and move" + bl_label = "Extrude Individual and Move" + bl_idname = "view3d.edit_mesh_extrude_individual_move" + + def execute(self, context): + mesh = context.object.data + select_mode = context.tool_settings.mesh_select_mode + + totface = mesh.total_face_sel + totedge = mesh.total_edge_sel + # totvert = mesh.total_vert_sel + + if select_mode[2] and totface == 1: + bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (False, False, True)}) + elif select_mode[2] and totface > 1: + bpy.ops.mesh.extrude_faces_move('INVOKE_REGION_WIN') + elif select_mode[1] and totedge >= 1: + bpy.ops.mesh.extrude_edges_move('INVOKE_REGION_WIN') + else: + bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN') + + # ignore return from operators above because they are 'RUNNING_MODAL', and cause this one not to be freed. [#24671] + return {'FINISHED'} + + def invoke(self, context, event): + return self.execute(context) + + +class VIEW3D_OT_edit_mesh_extrude_move(Operator): + "Extrude and move along normals" + bl_label = "Extrude and Move on Normals" + bl_idname = "view3d.edit_mesh_extrude_move_normal" + + def execute(self, context): + mesh = context.object.data + + totface = mesh.total_face_sel + totedge = mesh.total_edge_sel + # totvert = mesh.total_vert_sel + + if totface >= 1: + bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (False, False, True)}) + elif totedge == 1: + bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (True, True, False)}) + else: + bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN') + + # ignore return from operators above because they are 'RUNNING_MODAL', and cause this one not to be freed. [#24671] + return {'FINISHED'} + + def invoke(self, context, event): + return self.execute(context)
\ No newline at end of file diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index f784ea5025a..44344487a26 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1179,3 +1179,707 @@ class WM_OT_copy_prev_settings(Operator): return {'FINISHED'} return {'CANCELLED'} + + +class WM_OT_keyconfig_test(Operator): + "Test keyconfig for conflicts" + bl_idname = "wm.keyconfig_test" + bl_label = "Test Key Configuration for Conflicts" + + def testEntry(self, kc, entry, src=None, parent=None): + result = False + + def kmistr(kmi): + if km.is_modal: + s = ["kmi = km.keymap_items.new_modal(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value)] + else: + s = ["kmi = km.keymap_items.new(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, 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(", key_modifier=\'%s\'" % kmi.key_modifier) + + s.append(")\n") + + props = kmi.properties + + if props is not None: + export_properties("kmi.properties", props, s) + + return "".join(s).strip() + + idname, spaceid, regionid, children = entry + + km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid) + + if km: + km = km.active() + + if src: + for item in km.keymap_items: + if src.compare(item): + print("===========") + print(parent.name) + print(kmistr(src)) + print(km.name) + print(kmistr(item)) + result = True + + for child in children: + if self.testEntry(kc, child, src, parent): + result = True + else: + for i in range(len(km.keymap_items)): + src = km.keymap_items[i] + + for child in children: + if self.testEntry(kc, child, src, km): + result = True + + for j in range(len(km.keymap_items) - i - 1): + item = km.keymap_items[j + i + 1] + if src.compare(item): + print("===========") + print(km.name) + print(kmistr(src)) + print(kmistr(item)) + result = True + + for child in children: + if self.testEntry(kc, child): + result = True + + return result + + def testConfig(self, kc): + result = False + for entry in KM_HIERARCHY: + if self.testEntry(kc, entry): + result = True + return result + + def execute(self, context): + wm = context.window_manager + kc = wm.keyconfigs.default + + if self.testConfig(kc): + print("CONFLICT") + + return {'FINISHED'} + + +def _string_value(value): + if isinstance(value, str) or isinstance(value, bool) or isinstance(value, float) or isinstance(value, int): + result = repr(value) + elif getattr(value, '__len__', False): + return repr(list(value)) + else: + print("Export key configuration: can't write ", value) + + return result + + +class WM_OT_keyconfig_import(Operator): + "Import key configuration from a python script" + bl_idname = "wm.keyconfig_import" + bl_label = "Import Key Configuration..." + + filepath = StringProperty( + name="File Path", + description="Filepath to write file to", + default="keymap.py", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_text = BoolProperty( + name="Filter text", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + keep_original = BoolProperty( + name="Keep original", + description="Keep original file after copying to configuration folder", + default=True, + ) + + def execute(self, context): + from os.path import basename + import shutil + + if not self.filepath: + self.report({'ERROR'}, "Filepath not set") + return {'CANCELLED'} + + config_name = basename(self.filepath) + + path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", "keyconfig"), create=True) + path = os.path.join(path, config_name) + + try: + if self.keep_original: + shutil.copy(self.filepath, path) + else: + shutil.move(self.filepath, path) + except Exception as e: + self.report({'ERROR'}, "Installing keymap failed: %s" % e) + return {'CANCELLED'} + + # sneaky way to check we're actually running the code. + bpy.utils.keyconfig_set(path) + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + +# This operator is also used by interaction presets saving - AddPresetBase + + +class WM_OT_keyconfig_export(Operator): + "Export key configuration to a python script" + bl_idname = "wm.keyconfig_export" + bl_label = "Export Key Configuration..." + + filepath = StringProperty( + name="File Path", + description="Filepath to write file to", + default="keymap.py", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_text = BoolProperty( + name="Filter text", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + + def execute(self, context): + if not self.filepath: + raise Exception("Filepath not set") + + if not self.filepath.endswith('.py'): + self.filepath += '.py' + + f = open(self.filepath, "w") + if not f: + raise Exception("Could not open file") + + wm = context.window_manager + kc = wm.keyconfigs.active + + f.write("import bpy\n") + f.write("import os\n\n") + f.write("wm = bpy.context.window_manager\n") + f.write("kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0])\n\n") # keymap must be created by caller + + # 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. + + class FakeKeyConfig(): + keymaps = [] + edited_kc = FakeKeyConfig() + for km in wm.keyconfigs.user.keymaps: + if 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 = _merge_keymaps(edited_kc, kc) + else: + export_keymaps = _merge_keymaps(edited_kc, edited_kc) + + for km, kc_x in export_keymaps: + + km = km.active() + + f.write("# Map %s\n" % km.name) + f.write("km = kc.keymaps.new('%s', space_type='%s', region_type='%s', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.is_modal)) + for kmi in km.keymap_items: + if km.is_modal: + f.write("kmi = km.keymap_items.new_modal('%s', '%s', '%s'" % (kmi.propvalue, kmi.type, kmi.value)) + else: + f.write("kmi = km.keymap_items.new('%s', '%s', '%s'" % (kmi.idname, kmi.type, kmi.value)) + if kmi.any: + f.write(", any=True") + else: + if kmi.shift: + f.write(", shift=True") + if kmi.ctrl: + f.write(", ctrl=True") + if kmi.alt: + f.write(", alt=True") + if kmi.oskey: + f.write(", oskey=True") + if kmi.key_modifier and kmi.key_modifier != 'NONE': + f.write(", key_modifier='%s'" % kmi.key_modifier) + f.write(")\n") + + props = kmi.properties + + if props is not None: + f.write("".join(export_properties("kmi.properties", props))) + + f.write("\n") + + f.close() + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +class WM_OT_keymap_restore(Operator): + "Restore key map(s)" + bl_idname = "wm.keymap_restore" + bl_label = "Restore Key Map(s)" + + all = BoolProperty( + name="All Keymaps", + description="Restore all keymaps to default", + ) + + def execute(self, context): + wm = context.window_manager + + if self.all: + for km in wm.keyconfigs.user.keymaps: + km.restore_to_default() + else: + km = context.keymap + km.restore_to_default() + + return {'FINISHED'} + + +class WM_OT_keyitem_restore(Operator): + "Restore key map item" + bl_idname = "wm.keyitem_restore" + bl_label = "Restore Key Map Item" + + item_id = IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + keymap = getattr(context, "keymap", None) + return keymap + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + + if (not kmi.is_user_defined) and kmi.is_user_modified: + km.restore_item_to_default(kmi) + + return {'FINISHED'} + + +class WM_OT_keyitem_add(Operator): + "Add key map item" + bl_idname = "wm.keyitem_add" + bl_label = "Add Key Map Item" + + def execute(self, context): + km = context.keymap + + if km.is_modal: + km.keymap_items.new_modal("", 'A', 'PRESS') # kmi + else: + km.keymap_items.new("none", 'A', 'PRESS') # kmi + + # clear filter and expand keymap so we can see the newly added item + if context.space_data.filter_text != "": + context.space_data.filter_text = "" + km.show_expanded_items = True + km.show_expanded_children = True + + return {'FINISHED'} + + +class WM_OT_keyitem_remove(Operator): + "Remove key map item" + bl_idname = "wm.keyitem_remove" + bl_label = "Remove Key Map Item" + + item_id = IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + return hasattr(context, "keymap") + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + km.keymap_items.remove(kmi) + return {'FINISHED'} + + +class WM_OT_keyconfig_remove(Operator): + "Remove key config" + bl_idname = "wm.keyconfig_remove" + bl_label = "Remove Key Config" + + @classmethod + def poll(cls, context): + wm = context.window_manager + keyconf = wm.keyconfigs.active + return keyconf and keyconf.is_user_defined + + def execute(self, context): + wm = context.window_manager + keyconfig = wm.keyconfigs.active + wm.keyconfigs.remove(keyconfig) + return {'FINISHED'} + + +class WM_OT_operator_cheat_sheet(Operator): + bl_idname = "wm.operator_cheat_sheet" + bl_label = "Operator Cheat Sheet" + + def execute(self, context): + op_strings = [] + tot = 0 + for op_module_name in dir(bpy.ops): + op_module = getattr(bpy.ops, op_module_name) + for op_submodule_name in dir(op_module): + op = getattr(op_module, op_submodule_name) + text = repr(op) + if text.split("\n")[-1].startswith('bpy.ops.'): + op_strings.append(text) + tot += 1 + + op_strings.append('') + + textblock = bpy.data.texts.new("OperatorList.txt") + textblock.write('# %d Operators\n\n' % tot) + textblock.write('\n'.join(op_strings)) + self.report({'INFO'}, "See OperatorList.txt textblock") + return {'FINISHED'} + + +class WM_OT_addon_enable(Operator): + "Enable an addon" + bl_idname = "wm.addon_enable" + bl_label = "Enable Add-On" + + module = StringProperty( + name="Module", + description="Module name of the addon to enable", + ) + + def execute(self, context): + mod = addon_utils.enable(self.module) + + if mod: + info = addon_utils.module_bl_info(mod) + + info_ver = info.get("blender", (0, 0, 0)) + + if info_ver > bpy.app.version: + self.report({'WARNING'}, ("This script was written Blender " + "version %d.%d.%d and might not " + "function (correctly), " + "though it is enabled") % + info_ver) + return {'FINISHED'} + else: + return {'CANCELLED'} + + +class WM_OT_addon_disable(Operator): + "Disable an addon" + bl_idname = "wm.addon_disable" + bl_label = "Disable Add-On" + + module = StringProperty( + name="Module", + description="Module name of the addon to disable", + ) + + def execute(self, context): + addon_utils.disable(self.module) + return {'FINISHED'} + + +class WM_OT_addon_install(Operator): + "Install an addon" + bl_idname = "wm.addon_install" + bl_label = "Install Add-On..." + + overwrite = BoolProperty( + name="Overwrite", + description="Remove existing addons with the same ID", + default=True, + ) + target = EnumProperty( + name="Target Path", + items=(('DEFAULT', "Default", ""), + ('PREFS', "User Prefs", "")), + ) + + filepath = StringProperty( + name="File Path", + description="File path to write file to", + ) + filter_folder = BoolProperty( + name="Filter folders", + default=True, + options={'HIDDEN'}, + ) + filter_python = BoolProperty( + name="Filter python", + default=True, + options={'HIDDEN'}, + ) + filter_glob = StringProperty( + default="*.py;*.zip", + options={'HIDDEN'}, + ) + + @staticmethod + def _module_remove(path_addons, module): + module = os.path.splitext(module)[0] + for f in os.listdir(path_addons): + f_base = os.path.splitext(f)[0] + if f_base == module: + f_full = os.path.join(path_addons, f) + + if os.path.isdir(f_full): + os.rmdir(f_full) + else: + os.remove(f_full) + + def execute(self, context): + import traceback + import zipfile + import shutil + + pyfile = self.filepath + + if self.target == 'DEFAULT': + # dont use bpy.utils.script_paths("addons") because we may not be able to write to it. + path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True) + else: + path_addons = bpy.context.user_preferences.filepaths.script_directory + if path_addons: + path_addons = os.path.join(path_addons, "addons") + + if not path_addons: + self.report({'ERROR'}, "Failed to get addons path") + return {'CANCELLED'} + + # create dir is if missing. + if not os.path.exists(path_addons): + os.makedirs(path_addons) + + # Check if we are installing from a target path, + # doing so causes 2+ addons of same name or when the same from/to + # location is used, removal of the file! + addon_path = "" + pyfile_dir = os.path.dirname(pyfile) + for addon_path in addon_utils.paths(): + if os.path.samefile(pyfile_dir, addon_path): + self.report({'ERROR'}, "Source file is in the addon search path: %r" % addon_path) + return {'CANCELLED'} + del addon_path + del pyfile_dir + # done checking for exceptional case + + addons_old = {mod.__name__ for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)} + + #check to see if the file is in compressed format (.zip) + if zipfile.is_zipfile(pyfile): + try: + file_to_extract = zipfile.ZipFile(pyfile, 'r') + except: + traceback.print_exc() + return {'CANCELLED'} + + if self.overwrite: + for f in file_to_extract.namelist(): + WM_OT_addon_install._module_remove(path_addons, f) + else: + for f in file_to_extract.namelist(): + path_dest = os.path.join(path_addons, os.path.basename(f)) + if os.path.exists(path_dest): + self.report({'WARNING'}, "File already installed to %r\n" % path_dest) + return {'CANCELLED'} + + try: # extract the file to "addons" + file_to_extract.extractall(path_addons) + + # zip files can create this dir with metadata, don't need it + macosx_dir = os.path.join(path_addons, '__MACOSX') + if os.path.isdir(macosx_dir): + shutil.rmtree(macosx_dir) + + except: + traceback.print_exc() + return {'CANCELLED'} + + else: + path_dest = os.path.join(path_addons, os.path.basename(pyfile)) + + if self.overwrite: + WM_OT_addon_install._module_remove(path_addons, os.path.basename(pyfile)) + elif os.path.exists(path_dest): + self.report({'WARNING'}, "File already installed to %r\n" % path_dest) + return {'CANCELLED'} + + #if not compressed file just copy into the addon path + try: + shutil.copyfile(pyfile, path_dest) + + except: + traceback.print_exc() + return {'CANCELLED'} + + addons_new = {mod.__name__ for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)} - addons_old + addons_new.discard("modules") + + # disable any addons we may have enabled previously and removed. + # this is unlikely but do just incase. bug [#23978] + for new_addon in addons_new: + addon_utils.disable(new_addon) + + # possible the zip contains multiple addons, we could disallow this + # but for now just use the first + for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules): + if mod.__name__ in addons_new: + info = addon_utils.module_bl_info(mod) + + # show the newly installed addon. + context.window_manager.addon_filter = 'All' + context.window_manager.addon_search = info["name"] + break + + # incase a new module path was created to install this addon. + bpy.utils.refresh_script_paths() + + # TODO, should not be a warning. + # self.report({'WARNING'}, "File installed to '%s'\n" % path_dest) + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + wm.fileselect_add(self) + return {'RUNNING_MODAL'} + + +class WM_OT_addon_remove(Operator): + "Disable an addon" + bl_idname = "wm.addon_remove" + bl_label = "Remove Add-On" + + module = StringProperty( + name="Module", + description="Module name of the addon to remove", + ) + + @staticmethod + def path_from_addon(module): + for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules): + if mod.__name__ == module: + filepath = mod.__file__ + if os.path.exists(filepath): + if os.path.splitext(os.path.basename(filepath))[0] == "__init__": + return os.path.dirname(filepath), True + else: + return filepath, False + return None, False + + def execute(self, context): + path, isdir = WM_OT_addon_remove.path_from_addon(self.module) + if path is None: + self.report('WARNING', "Addon path %r could not be found" % path) + return {'CANCELLED'} + + # incase its enabled + addon_utils.disable(self.module) + + import shutil + if isdir: + shutil.rmtree(path) + else: + os.remove(path) + + context.area.tag_redraw() + return {'FINISHED'} + + # lame confirmation check + def draw(self, context): + self.layout.label(text="Remove Addon: %r?" % self.module) + path, isdir = WM_OT_addon_remove.path_from_addon(self.module) + self.layout.label(text="Path: %r" % path) + + def invoke(self, context, event): + wm = context.window_manager + return wm.invoke_props_dialog(self, width=600) + + +class WM_OT_addon_expand(Operator): + "Display more information on this add-on" + bl_idname = "wm.addon_expand" + bl_label = "" + + module = StringProperty( + name="Module", + description="Module name of the addon to expand", + ) + + def execute(self, context): + module_name = self.module + + # unlikely to fail, module should have already been imported + try: + # mod = __import__(module_name) + mod = USERPREF_PT_addons.module_get(module_name) + except: + import traceback + traceback.print_exc() + return {'CANCELLED'} + + info = addon_utils.module_bl_info(mod) + info["show_expanded"] = not info["show_expanded"] + return {'FINISHED'} diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 5a25e608a39..167cead9a3b 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -18,7 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Operator, Panel +from bpy.types import Panel from rna_prop_ui import PropertyPanel @@ -224,112 +224,5 @@ class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel): _context_path = "scene" _property_type = bpy.types.Scene -# XXX, move operator to op/ dir - - -class ANIM_OT_keying_set_export(Operator): - "Export Keying Set to a python script" - bl_idname = "anim.keying_set_export" - bl_label = "Export Keying Set..." - - filepath = bpy.props.StringProperty(name="File Path", description="Filepath to write file to") - filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'}) - filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'}) - filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'}) - - def execute(self, context): - if not self.filepath: - raise Exception("Filepath not set") - - f = open(self.filepath, "w") - if not f: - raise Exception("Could not open file") - - scene = context.scene - ks = scene.keying_sets.active - - f.write("# Keying Set: %s\n" % ks.name) - - f.write("import bpy\n\n") - f.write("scene= bpy.data.scenes[0]\n\n") # XXX, why not use the current scene? - - # Add KeyingSet and set general settings - f.write("# Keying Set Level declarations\n") - f.write("ks= scene.keying_sets.new(name=\"%s\")\n" % ks.name) - - if not ks.is_path_absolute: - f.write("ks.is_path_absolute = False\n") - f.write("\n") - - f.write("ks.bl_options = %r\n" % ks.bl_options) - f.write("\n") - - # generate and write set of lookups for id's used in paths - id_to_paths_cache = {} # cache for syncing ID-blocks to bpy paths + shorthands - - for ksp in ks.paths: - if ksp.id is None: - continue - if ksp.id in id_to_paths_cache: - continue - - # - idtype_list is used to get the list of id-datablocks from bpy.data.* - # since this info isn't available elsewhere - # - id.bl_rna.name gives a name suitable for UI, - # with a capitalised first letter, but we need - # the plural form that's all lower case - idtype_list = ksp.id.bl_rna.name.lower() + "s" - id_bpy_path = "bpy.data.%s[\"%s\"]" % (idtype_list, ksp.id.name) - - # shorthand ID for the ID-block (as used in the script) - short_id = "id_%d" % len(id_to_paths_cache) - - # store this in the cache now - id_to_paths_cache[ksp.id] = [short_id, id_bpy_path] - - f.write("# ID's that are commonly used\n") - for id_pair in id_to_paths_cache.values(): - f.write("%s = %s\n" % (id_pair[0], id_pair[1])) - f.write("\n") - - # write paths - f.write("# Path Definitions\n") - for ksp in ks.paths: - f.write("ksp = ks.paths.add(") - - # id-block + data_path - if ksp.id: - # find the relevant shorthand from the cache - id_bpy_path = id_to_paths_cache[ksp.id][0] - else: - id_bpy_path = "None" # XXX... - f.write("%s, '%s'" % (id_bpy_path, ksp.data_path)) - - # array index settings (if applicable) - if ksp.use_entire_array: - f.write(", index=-1") - else: - f.write(", index=%d" % ksp.array_index) - - # grouping settings (if applicable) - # NOTE: the current default is KEYINGSET, but if this changes, change this code too - if ksp.group_method == 'NAMED': - f.write(", group_method='%s', group_name=\"%s\"" % (ksp.group_method, ksp.group)) - elif ksp.group_method != 'KEYINGSET': - f.write(", group_method='%s'" % ksp.group_method) - - # finish off - f.write(")\n") - - f.write("\n") - f.close() - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} - if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index cbbefa01a3c..a1818c395a2 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -18,8 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu, Operator -from bpy.props import StringProperty +from bpy.types import Header, Menu class CONSOLE_HT_header(Header): @@ -79,87 +78,5 @@ def add_scrollback(text, text_type): bpy.ops.console.scrollback_append(text=l.replace('\t', ' '), type=text_type) - -class ConsoleExec(Operator): - '''Execute the current console line as a python expression''' - bl_idname = "console.execute" - bl_label = "Console Execute" - - def execute(self, context): - sc = context.space_data - - module = __import__("console_" + sc.language) - execute = getattr(module, "execute", None) - - if execute: - return execute(context) - else: - print("Error: bpy.ops.console.execute_" + sc.language + " - not found") - return {'FINISHED'} - - -class ConsoleAutocomplete(Operator): - '''Evaluate the namespace up until the cursor and give a list of options or complete the name if there is only one''' - bl_idname = "console.autocomplete" - bl_label = "Console Autocomplete" - - def execute(self, context): - sc = context.space_data - module = __import__("console_" + sc.language) - autocomplete = getattr(module, "autocomplete", None) - - if autocomplete: - return autocomplete(context) - else: - print("Error: bpy.ops.console.autocomplete_" + sc.language + " - not found") - return {'FINISHED'} - - -class ConsoleBanner(Operator): - '''Print a message whem the terminal initializes''' - bl_idname = "console.banner" - bl_label = "Console Banner" - - def execute(self, context): - sc = context.space_data - - # default to python - if not sc.language: - sc.language = 'python' - - module = __import__("console_" + sc.language) - banner = getattr(module, "banner", None) - - if banner: - return banner(context) - else: - print("Error: bpy.ops.console.banner_" + sc.language + " - not found") - return {'FINISHED'} - - -class ConsoleLanguage(Operator): - '''Set the current language for this console''' - bl_idname = "console.language" - bl_label = "Console Language" - - language = StringProperty( - name="Language", - maxlen=32, - ) - - def execute(self, context): - sc = context.space_data - - # defailt to python - sc.language = self.language - - bpy.ops.console.banner() - - # insert a new blank line - bpy.ops.console.history_append(text="", current_character=0, - remove_duplicates=True) - - return {'FINISHED'} - if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index debe82e7ab2..644676310fc 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -18,7 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu, Operator +from bpy.types import Header, Menu class INFO_HT_header(Header): @@ -373,7 +373,7 @@ class INFO_MT_help(Menu): layout.separator() layout.operator("wm.url_open", text="Python API Reference", icon='URL').url = bpy.types.WM_OT_doc_view._prefix - layout.operator("help.operator_cheat_sheet", icon='TEXT') + layout.operator("wm.operator_cheat_sheet", icon='TEXT') layout.operator("wm.sysinfo", icon='TEXT') layout.separator() if sys.platform[:3] == "win": @@ -384,33 +384,5 @@ class INFO_MT_help(Menu): layout.separator() layout.operator("wm.splash", icon='BLENDER') - -# Help operators - - -class HELP_OT_operator_cheat_sheet(Operator): - bl_idname = "help.operator_cheat_sheet" - bl_label = "Operator Cheat Sheet" - - def execute(self, context): - op_strings = [] - tot = 0 - for op_module_name in dir(bpy.ops): - op_module = getattr(bpy.ops, op_module_name) - for op_submodule_name in dir(op_module): - op = getattr(op_module, op_submodule_name) - text = repr(op) - if text.split("\n")[-1].startswith('bpy.ops.'): - op_strings.append(text) - tot += 1 - - op_strings.append('') - - textblock = bpy.data.texts.new("OperatorList.txt") - textblock.write('# %d Operators\n\n' % tot) - textblock.write('\n'.join(op_strings)) - self.report({'INFO'}, "See OperatorList.txt textblock") - return {'FINISHED'} - if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 9573f6b0f5c..9e55c8ad815 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -18,7 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu, Operator, Panel +from bpy.types import Header, Menu, Panel import os import addon_utils @@ -1074,292 +1074,5 @@ class USERPREF_PT_addons(Panel): if is_enabled: row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name - -class WM_OT_addon_enable(Operator): - "Enable an addon" - bl_idname = "wm.addon_enable" - bl_label = "Enable Add-On" - - module = StringProperty( - name="Module", - description="Module name of the addon to enable", - ) - - def execute(self, context): - mod = addon_utils.enable(self.module) - - if mod: - info = addon_utils.module_bl_info(mod) - - info_ver = info.get("blender", (0, 0, 0)) - - if info_ver > bpy.app.version: - self.report({'WARNING'}, ("This script was written Blender " - "version %d.%d.%d and might not " - "function (correctly), " - "though it is enabled") % - info_ver) - return {'FINISHED'} - else: - return {'CANCELLED'} - - -class WM_OT_addon_disable(Operator): - "Disable an addon" - bl_idname = "wm.addon_disable" - bl_label = "Disable Add-On" - - module = StringProperty( - name="Module", - description="Module name of the addon to disable", - ) - - def execute(self, context): - addon_utils.disable(self.module) - return {'FINISHED'} - - -class WM_OT_addon_install(Operator): - "Install an addon" - bl_idname = "wm.addon_install" - bl_label = "Install Add-On..." - - overwrite = BoolProperty( - name="Overwrite", - description="Remove existing addons with the same ID", - default=True, - ) - target = EnumProperty( - name="Target Path", - items=(('DEFAULT', "Default", ""), - ('PREFS', "User Prefs", "")), - ) - - filepath = StringProperty( - name="File Path", - description="File path to write file to", - ) - filter_folder = BoolProperty( - name="Filter folders", - default=True, - options={'HIDDEN'}, - ) - filter_python = BoolProperty( - name="Filter python", - default=True, - options={'HIDDEN'}, - ) - filter_glob = StringProperty( - default="*.py;*.zip", - options={'HIDDEN'}, - ) - - @staticmethod - def _module_remove(path_addons, module): - module = os.path.splitext(module)[0] - for f in os.listdir(path_addons): - f_base = os.path.splitext(f)[0] - if f_base == module: - f_full = os.path.join(path_addons, f) - - if os.path.isdir(f_full): - os.rmdir(f_full) - else: - os.remove(f_full) - - def execute(self, context): - import traceback - import zipfile - import shutil - - pyfile = self.filepath - - if self.target == 'DEFAULT': - # dont use bpy.utils.script_paths("addons") because we may not be able to write to it. - path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True) - else: - path_addons = bpy.context.user_preferences.filepaths.script_directory - if path_addons: - path_addons = os.path.join(path_addons, "addons") - - if not path_addons: - self.report({'ERROR'}, "Failed to get addons path") - return {'CANCELLED'} - - # create dir is if missing. - if not os.path.exists(path_addons): - os.makedirs(path_addons) - - # Check if we are installing from a target path, - # doing so causes 2+ addons of same name or when the same from/to - # location is used, removal of the file! - addon_path = "" - pyfile_dir = os.path.dirname(pyfile) - for addon_path in addon_utils.paths(): - if os.path.samefile(pyfile_dir, addon_path): - self.report({'ERROR'}, "Source file is in the addon search path: %r" % addon_path) - return {'CANCELLED'} - del addon_path - del pyfile_dir - # done checking for exceptional case - - addons_old = {mod.__name__ for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)} - - #check to see if the file is in compressed format (.zip) - if zipfile.is_zipfile(pyfile): - try: - file_to_extract = zipfile.ZipFile(pyfile, 'r') - except: - traceback.print_exc() - return {'CANCELLED'} - - if self.overwrite: - for f in file_to_extract.namelist(): - WM_OT_addon_install._module_remove(path_addons, f) - else: - for f in file_to_extract.namelist(): - path_dest = os.path.join(path_addons, os.path.basename(f)) - if os.path.exists(path_dest): - self.report({'WARNING'}, "File already installed to %r\n" % path_dest) - return {'CANCELLED'} - - try: # extract the file to "addons" - file_to_extract.extractall(path_addons) - - # zip files can create this dir with metadata, don't need it - macosx_dir = os.path.join(path_addons, '__MACOSX') - if os.path.isdir(macosx_dir): - shutil.rmtree(macosx_dir) - - except: - traceback.print_exc() - return {'CANCELLED'} - - else: - path_dest = os.path.join(path_addons, os.path.basename(pyfile)) - - if self.overwrite: - WM_OT_addon_install._module_remove(path_addons, os.path.basename(pyfile)) - elif os.path.exists(path_dest): - self.report({'WARNING'}, "File already installed to %r\n" % path_dest) - return {'CANCELLED'} - - #if not compressed file just copy into the addon path - try: - shutil.copyfile(pyfile, path_dest) - - except: - traceback.print_exc() - return {'CANCELLED'} - - addons_new = {mod.__name__ for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules)} - addons_old - addons_new.discard("modules") - - # disable any addons we may have enabled previously and removed. - # this is unlikely but do just incase. bug [#23978] - for new_addon in addons_new: - addon_utils.disable(new_addon) - - # possible the zip contains multiple addons, we could disallow this - # but for now just use the first - for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules): - if mod.__name__ in addons_new: - info = addon_utils.module_bl_info(mod) - - # show the newly installed addon. - context.window_manager.addon_filter = 'All' - context.window_manager.addon_search = info["name"] - break - - # incase a new module path was created to install this addon. - bpy.utils.refresh_script_paths() - - # TODO, should not be a warning. - # self.report({'WARNING'}, "File installed to '%s'\n" % path_dest) - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} - - -class WM_OT_addon_remove(Operator): - "Disable an addon" - bl_idname = "wm.addon_remove" - bl_label = "Remove Add-On" - - module = StringProperty( - name="Module", - description="Module name of the addon to remove", - ) - - @staticmethod - def path_from_addon(module): - for mod in addon_utils.modules(USERPREF_PT_addons._addons_fake_modules): - if mod.__name__ == module: - filepath = mod.__file__ - if os.path.exists(filepath): - if os.path.splitext(os.path.basename(filepath))[0] == "__init__": - return os.path.dirname(filepath), True - else: - return filepath, False - return None, False - - def execute(self, context): - path, isdir = WM_OT_addon_remove.path_from_addon(self.module) - if path is None: - self.report('WARNING', "Addon path %r could not be found" % path) - return {'CANCELLED'} - - # incase its enabled - addon_utils.disable(self.module) - - import shutil - if isdir: - shutil.rmtree(path) - else: - os.remove(path) - - context.area.tag_redraw() - return {'FINISHED'} - - # lame confirmation check - def draw(self, context): - self.layout.label(text="Remove Addon: %r?" % self.module) - path, isdir = WM_OT_addon_remove.path_from_addon(self.module) - self.layout.label(text="Path: %r" % path) - - def invoke(self, context, event): - wm = context.window_manager - return wm.invoke_props_dialog(self, width=600) - - -class WM_OT_addon_expand(Operator): - "Display more information on this add-on" - bl_idname = "wm.addon_expand" - bl_label = "" - - module = StringProperty( - name="Module", - description="Module name of the addon to expand", - ) - - def execute(self, context): - module_name = self.module - - # unlikely to fail, module should have already been imported - try: - # mod = __import__(module_name) - mod = USERPREF_PT_addons.module_get(module_name) - except: - import traceback - traceback.print_exc() - return {'CANCELLED'} - - info = addon_utils.module_bl_info(mod) - info["show_expanded"] = not info["show_expanded"] - return {'FINISHED'} - if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py index e6b1866baf5..dcf9a7d2d7f 100644 --- a/release/scripts/startup/bl_ui/space_userpref_keymap.py +++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py @@ -18,7 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Menu, Operator, OperatorProperties +from bpy.types import Menu, OperatorProperties import os @@ -401,9 +401,6 @@ class InputKeyMapPanel: self.draw_hierarchy(display_keymaps, col) -from bpy.props import StringProperty, BoolProperty, IntProperty - - def export_properties(prefix, properties, lines=None): if lines is None: lines = [] @@ -419,397 +416,5 @@ def export_properties(prefix, properties, lines=None): lines.append("%s.%s = %s\n" % (prefix, pname, value)) return lines - -class WM_OT_keyconfig_test(Operator): - "Test keyconfig for conflicts" - bl_idname = "wm.keyconfig_test" - bl_label = "Test Key Configuration for Conflicts" - - def testEntry(self, kc, entry, src=None, parent=None): - result = False - - def kmistr(kmi): - if km.is_modal: - s = ["kmi = km.keymap_items.new_modal(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value)] - else: - s = ["kmi = km.keymap_items.new(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, 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(", key_modifier=\'%s\'" % kmi.key_modifier) - - s.append(")\n") - - props = kmi.properties - - if props is not None: - export_properties("kmi.properties", props, s) - - return "".join(s).strip() - - idname, spaceid, regionid, children = entry - - km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid) - - if km: - km = km.active() - - if src: - for item in km.keymap_items: - if src.compare(item): - print("===========") - print(parent.name) - print(kmistr(src)) - print(km.name) - print(kmistr(item)) - result = True - - for child in children: - if self.testEntry(kc, child, src, parent): - result = True - else: - for i in range(len(km.keymap_items)): - src = km.keymap_items[i] - - for child in children: - if self.testEntry(kc, child, src, km): - result = True - - for j in range(len(km.keymap_items) - i - 1): - item = km.keymap_items[j + i + 1] - if src.compare(item): - print("===========") - print(km.name) - print(kmistr(src)) - print(kmistr(item)) - result = True - - for child in children: - if self.testEntry(kc, child): - result = True - - return result - - def testConfig(self, kc): - result = False - for entry in KM_HIERARCHY: - if self.testEntry(kc, entry): - result = True - return result - - def execute(self, context): - wm = context.window_manager - kc = wm.keyconfigs.default - - if self.testConfig(kc): - print("CONFLICT") - - return {'FINISHED'} - - -def _string_value(value): - if isinstance(value, str) or isinstance(value, bool) or isinstance(value, float) or isinstance(value, int): - result = repr(value) - elif getattr(value, '__len__', False): - return repr(list(value)) - else: - print("Export key configuration: can't write ", value) - - return result - - -class WM_OT_keyconfig_import(Operator): - "Import key configuration from a python script" - bl_idname = "wm.keyconfig_import" - bl_label = "Import Key Configuration..." - - filepath = StringProperty( - name="File Path", - description="Filepath to write file to", - default="keymap.py", - ) - filter_folder = BoolProperty( - name="Filter folders", - default=True, - options={'HIDDEN'}, - ) - filter_text = BoolProperty( - name="Filter text", - default=True, - options={'HIDDEN'}, - ) - filter_python = BoolProperty( - name="Filter python", - default=True, - options={'HIDDEN'}, - ) - keep_original = BoolProperty( - name="Keep original", - description="Keep original file after copying to configuration folder", - default=True, - ) - - def execute(self, context): - from os.path import basename - import shutil - - if not self.filepath: - self.report({'ERROR'}, "Filepath not set") - return {'CANCELLED'} - - config_name = basename(self.filepath) - - path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", "keyconfig"), create=True) - path = os.path.join(path, config_name) - - try: - if self.keep_original: - shutil.copy(self.filepath, path) - else: - shutil.move(self.filepath, path) - except Exception as e: - self.report({'ERROR'}, "Installing keymap failed: %s" % e) - return {'CANCELLED'} - - # sneaky way to check we're actually running the code. - bpy.utils.keyconfig_set(path) - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} - -# This operator is also used by interaction presets saving - AddPresetBase - - -class WM_OT_keyconfig_export(Operator): - "Export key configuration to a python script" - bl_idname = "wm.keyconfig_export" - bl_label = "Export Key Configuration..." - - filepath = StringProperty( - name="File Path", - description="Filepath to write file to", - default="keymap.py", - ) - filter_folder = BoolProperty( - name="Filter folders", - default=True, - options={'HIDDEN'}, - ) - filter_text = BoolProperty( - name="Filter text", - default=True, - options={'HIDDEN'}, - ) - filter_python = BoolProperty( - name="Filter python", - default=True, - options={'HIDDEN'}, - ) - - def execute(self, context): - if not self.filepath: - raise Exception("Filepath not set") - - if not self.filepath.endswith('.py'): - self.filepath += '.py' - - f = open(self.filepath, "w") - if not f: - raise Exception("Could not open file") - - wm = context.window_manager - kc = wm.keyconfigs.active - - f.write("import bpy\n") - f.write("import os\n\n") - f.write("wm = bpy.context.window_manager\n") - f.write("kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0])\n\n") # keymap must be created by caller - - # 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. - - class FakeKeyConfig(): - keymaps = [] - edited_kc = FakeKeyConfig() - for km in wm.keyconfigs.user.keymaps: - if 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 = _merge_keymaps(edited_kc, kc) - else: - export_keymaps = _merge_keymaps(edited_kc, edited_kc) - - for km, kc_x in export_keymaps: - - km = km.active() - - f.write("# Map %s\n" % km.name) - f.write("km = kc.keymaps.new('%s', space_type='%s', region_type='%s', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.is_modal)) - for kmi in km.keymap_items: - if km.is_modal: - f.write("kmi = km.keymap_items.new_modal('%s', '%s', '%s'" % (kmi.propvalue, kmi.type, kmi.value)) - else: - f.write("kmi = km.keymap_items.new('%s', '%s', '%s'" % (kmi.idname, kmi.type, kmi.value)) - if kmi.any: - f.write(", any=True") - else: - if kmi.shift: - f.write(", shift=True") - if kmi.ctrl: - f.write(", ctrl=True") - if kmi.alt: - f.write(", alt=True") - if kmi.oskey: - f.write(", oskey=True") - if kmi.key_modifier and kmi.key_modifier != 'NONE': - f.write(", key_modifier='%s'" % kmi.key_modifier) - f.write(")\n") - - props = kmi.properties - - if props is not None: - f.write("".join(export_properties("kmi.properties", props))) - - f.write("\n") - - f.close() - - return {'FINISHED'} - - def invoke(self, context, event): - wm = context.window_manager - wm.fileselect_add(self) - return {'RUNNING_MODAL'} - - -class WM_OT_keymap_restore(Operator): - "Restore key map(s)" - bl_idname = "wm.keymap_restore" - bl_label = "Restore Key Map(s)" - - all = BoolProperty( - name="All Keymaps", - description="Restore all keymaps to default", - ) - - def execute(self, context): - wm = context.window_manager - - if self.all: - for km in wm.keyconfigs.user.keymaps: - km.restore_to_default() - else: - km = context.keymap - km.restore_to_default() - - return {'FINISHED'} - - -class WM_OT_keyitem_restore(Operator): - "Restore key map item" - bl_idname = "wm.keyitem_restore" - bl_label = "Restore Key Map Item" - - item_id = IntProperty( - name="Item Identifier", - description="Identifier of the item to remove", - ) - - @classmethod - def poll(cls, context): - keymap = getattr(context, "keymap", None) - return keymap - - def execute(self, context): - km = context.keymap - kmi = km.keymap_items.from_id(self.item_id) - - if (not kmi.is_user_defined) and kmi.is_user_modified: - km.restore_item_to_default(kmi) - - return {'FINISHED'} - - -class WM_OT_keyitem_add(Operator): - "Add key map item" - bl_idname = "wm.keyitem_add" - bl_label = "Add Key Map Item" - - def execute(self, context): - km = context.keymap - - if km.is_modal: - km.keymap_items.new_modal("", 'A', 'PRESS') # kmi - else: - km.keymap_items.new("none", 'A', 'PRESS') # kmi - - # clear filter and expand keymap so we can see the newly added item - if context.space_data.filter_text != "": - context.space_data.filter_text = "" - km.show_expanded_items = True - km.show_expanded_children = True - - return {'FINISHED'} - - -class WM_OT_keyitem_remove(Operator): - "Remove key map item" - bl_idname = "wm.keyitem_remove" - bl_label = "Remove Key Map Item" - - item_id = IntProperty( - name="Item Identifier", - description="Identifier of the item to remove", - ) - - @classmethod - def poll(cls, context): - return hasattr(context, "keymap") - - def execute(self, context): - km = context.keymap - kmi = km.keymap_items.from_id(self.item_id) - km.keymap_items.remove(kmi) - return {'FINISHED'} - - -class WM_OT_keyconfig_remove(Operator): - "Remove key config" - bl_idname = "wm.keyconfig_remove" - bl_label = "Remove Key Config" - - @classmethod - def poll(cls, context): - wm = context.window_manager - keyconf = wm.keyconfigs.active - return keyconf and keyconf.is_user_defined - - def execute(self, context): - wm = context.window_manager - keyconfig = wm.keyconfigs.active - wm.keyconfigs.remove(keyconfig) - return {'FINISHED'} - if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 357c673edbd..f9e42862b9c 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -18,7 +18,7 @@ # <pep8 compliant> import bpy -from bpy.types import Header, Menu, Operator, Panel +from bpy.types import Header, Menu, Panel class VIEW3D_HT_header(Header): @@ -1551,61 +1551,6 @@ class VIEW3D_MT_edit_mesh_extrude(Menu): self._extrude_funcs[menu_id](layout) -class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator): - "Extrude individual elements and move" - bl_label = "Extrude Individual and Move" - bl_idname = "view3d.edit_mesh_extrude_individual_move" - - def execute(self, context): - mesh = context.object.data - select_mode = context.tool_settings.mesh_select_mode - - totface = mesh.total_face_sel - totedge = mesh.total_edge_sel - # totvert = mesh.total_vert_sel - - if select_mode[2] and totface == 1: - bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (False, False, True)}) - elif select_mode[2] and totface > 1: - bpy.ops.mesh.extrude_faces_move('INVOKE_REGION_WIN') - elif select_mode[1] and totedge >= 1: - bpy.ops.mesh.extrude_edges_move('INVOKE_REGION_WIN') - else: - bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN') - - # ignore return from operators above because they are 'RUNNING_MODAL', and cause this one not to be freed. [#24671] - return {'FINISHED'} - - def invoke(self, context, event): - return self.execute(context) - - -class VIEW3D_OT_edit_mesh_extrude_move(Operator): - "Extrude and move along normals" - bl_label = "Extrude and Move on Normals" - bl_idname = "view3d.edit_mesh_extrude_move_normal" - - def execute(self, context): - mesh = context.object.data - - totface = mesh.total_face_sel - totedge = mesh.total_edge_sel - # totvert = mesh.total_vert_sel - - if totface >= 1: - bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (False, False, True)}) - elif totedge == 1: - bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (True, True, False)}) - else: - bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN') - - # ignore return from operators above because they are 'RUNNING_MODAL', and cause this one not to be freed. [#24671] - return {'FINISHED'} - - def invoke(self, context, event): - return self.execute(context) - - class VIEW3D_MT_edit_mesh_vertices(Menu): bl_label = "Vertices" |