forked from bartvdbraak/blender
2.6 Python UI files:
* Moved Operators from bl_ui into bl_operators. * Renamed HELP_OT_operator_cheat_sheet to WM_OT_operator_cheat_sheet.
This commit is contained in:
parent
48918130a1
commit
e17ee1b415
@ -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)
|
||||
|
127
release/scripts/startup/bl_operators/anim.py
Normal file
127
release/scripts/startup/bl_operators/anim.py
Normal file
@ -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'}
|
106
release/scripts/startup/bl_operators/console.py
Normal file
106
release/scripts/startup/bl_operators/console.py
Normal file
@ -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'}
|
||||
|
77
release/scripts/startup/bl_operators/view3d.py
Normal file
77
release/scripts/startup/bl_operators/view3d.py
Normal file
@ -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)
|
@ -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'}
|
||||
|
@ -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__)
|
||||
|
@ -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__)
|
||||
|
@ -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__)
|
||||
|
@ -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__)
|
||||
|
@ -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__)
|
||||
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user