forked from bartvdbraak/blender
keyconfig updates/changes
- use preset subclass with funcs for updating the keyconfig - keyconfig filenames are used for the UI names as with presets (so separation anymore) - keyconfig's are stored in the preset dir (scripts/cfg dir removed) - only the active keyconfig script is loaded - some bugfixes for saving keymaps - user interactions no longer saves keyconfigs too, I think this needs to be re-worked. developer note... multiple keyconfigs at once are not really needed now that they are stored & accessed directly in python. for now I left it alone but we could consider to remove this capability in the future.
This commit is contained in:
parent
ce98d6ae17
commit
8d0c01e6e2
@ -182,7 +182,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
|
||||
user_path = user_script_path()
|
||||
|
||||
for base_path in script_paths():
|
||||
for path_subdir in ("", "ui", "op", "io", "cfg", "keyingsets", "modules"):
|
||||
for path_subdir in ("", "ui", "op", "io", "keyingsets", "modules"):
|
||||
path = _os.path.join(base_path, path_subdir)
|
||||
if _os.path.isdir(path):
|
||||
_sys_path_ensure(path)
|
||||
@ -202,6 +202,13 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
|
||||
# deal with addons seperately
|
||||
addon_reset_all()
|
||||
|
||||
|
||||
# run the active integration preset
|
||||
filepath = preset_find(_bpy.context.user_preferences.inputs.active_keyconfig, "keyconfig")
|
||||
if filepath:
|
||||
keyconfig_set(filepath)
|
||||
|
||||
|
||||
if reload_scripts:
|
||||
import gc
|
||||
print("gc.collect() -> %d" % gc.collect())
|
||||
@ -474,6 +481,9 @@ def addon_reset_all():
|
||||
addon_disable(mod_name)
|
||||
|
||||
def preset_find(name, preset_path, display_name=False):
|
||||
if not name:
|
||||
return None
|
||||
|
||||
for directory in preset_paths(preset_path):
|
||||
|
||||
if display_name:
|
||||
@ -488,4 +498,38 @@ def preset_find(name, preset_path, display_name=False):
|
||||
if filename:
|
||||
filepath = _os.path.join(directory, filename)
|
||||
if _os.path.exists(filepath):
|
||||
return filepath\
|
||||
return filepath
|
||||
|
||||
|
||||
def keyconfig_set(filepath):
|
||||
from os.path import basename, splitext
|
||||
|
||||
print("loading preset:", filepath)
|
||||
keyconfigs = _bpy.context.window_manager.keyconfigs
|
||||
kc_orig = keyconfigs.active
|
||||
|
||||
keyconfigs_old = keyconfigs[:]
|
||||
|
||||
try:
|
||||
exec(compile(open(filepath).read(), filepath, 'exec'), {"__file__": filepath})
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
kc_new = [kc for kc in keyconfigs if kc not in keyconfigs_old][0]
|
||||
|
||||
kc_new.name = ""
|
||||
|
||||
# remove duplicates
|
||||
name = splitext(basename(filepath))[0]
|
||||
while True:
|
||||
kc_dupe = keyconfigs.get(name)
|
||||
if kc_dupe:
|
||||
keyconfigs.remove(kc_dupe)
|
||||
else:
|
||||
break
|
||||
|
||||
kc_new.name = name
|
||||
keyconfigs.active = kc_new
|
||||
|
||||
|
||||
|
@ -33,13 +33,18 @@ class AddPresetBase():
|
||||
name = bpy.props.StringProperty(name="Name", description="Name of the preset, used to make the path name", maxlen=64, default="")
|
||||
remove_active = bpy.props.BoolProperty(default=False, options={'HIDDEN'})
|
||||
|
||||
def _as_filename(self, name): # could reuse for other presets
|
||||
for char in " !@#$%^&*(){}:\";'[]<>,./?":
|
||||
@staticmethod
|
||||
def as_filename(name): # could reuse for other presets
|
||||
for char in " !@#$%^&*(){}:\";'[]<>,.\\/?":
|
||||
name = name.replace(char, '_')
|
||||
return name.lower().strip()
|
||||
|
||||
def execute(self, context):
|
||||
import os
|
||||
|
||||
if hasattr(self, "pre_cb"):
|
||||
self.pre_cb(context)
|
||||
|
||||
preset_menu_class = getattr(bpy.types, self.preset_menu)
|
||||
|
||||
if not self.remove_active:
|
||||
@ -47,15 +52,14 @@ class AddPresetBase():
|
||||
if not self.name:
|
||||
return {'FINISHED'}
|
||||
|
||||
filename = self._as_filename(self.name) + ".py"
|
||||
filename = self.as_filename(self.name)
|
||||
|
||||
target_path = bpy.utils.preset_paths(self.preset_subdir)[0] # we need some way to tell the user and system preset path
|
||||
|
||||
filepath = os.path.join(target_path, filename)
|
||||
if getattr(self, "save_keyconfig", False):
|
||||
bpy.ops.wm.keyconfig_export(filepath=filepath, kc_name=self.name)
|
||||
file_preset = open(filepath, 'a')
|
||||
file_preset.write("wm.keyconfigs.active = kc\n\n")
|
||||
filepath = os.path.join(target_path, filename) + ".py"
|
||||
|
||||
if hasattr(self, "add"):
|
||||
self.add(context, filepath)
|
||||
else:
|
||||
file_preset = open(filepath, 'w')
|
||||
file_preset.write("import bpy\n")
|
||||
@ -73,12 +77,16 @@ class AddPresetBase():
|
||||
|
||||
# fairly sloppy but convenient.
|
||||
filepath = bpy.utils.preset_find(preset_active, self.preset_subdir)
|
||||
|
||||
if not filepath:
|
||||
filepath = bpy.utils.preset_find(preset_active, self.preset_subdir, display_name=True)
|
||||
|
||||
if not filepath:
|
||||
return {'CANCELLED'}
|
||||
|
||||
if hasattr(self, "remove"):
|
||||
self.remove(context, filepath)
|
||||
else:
|
||||
try:
|
||||
os.remove(filepath)
|
||||
except:
|
||||
@ -86,7 +94,10 @@ class AddPresetBase():
|
||||
traceback.print_exc()
|
||||
|
||||
# XXX, stupid!
|
||||
preset_menu_class.bl_label = bpy.path.display_name(self.preset_menu.replace("_MT_", " ").lower())
|
||||
preset_menu_class.bl_label = "Presets"
|
||||
|
||||
if hasattr(self, "post_cb"):
|
||||
self.post_cb(context)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@ -218,7 +229,6 @@ class AddPresetInteraction(AddPresetBase, bpy.types.Operator):
|
||||
bl_idname = "wm.interaction_preset_add"
|
||||
bl_label = "Add Interaction Preset"
|
||||
preset_menu = "USERPREF_MT_interaction_presets"
|
||||
save_keyconfig = True
|
||||
|
||||
preset_values = [
|
||||
"bpy.context.user_preferences.edit.use_drag_immediately",
|
||||
@ -236,6 +246,29 @@ class AddPresetInteraction(AddPresetBase, bpy.types.Operator):
|
||||
preset_subdir = "interaction"
|
||||
|
||||
|
||||
class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator):
|
||||
'''Add a Keyconfig Preset'''
|
||||
bl_idname = "wm.keyconfig_preset_add"
|
||||
bl_label = "Add Keyconfig Preset"
|
||||
preset_menu = "PREFS_MT_keyconfigs"
|
||||
preset_subdir = "keyconfig"
|
||||
|
||||
def add(self, context, filepath):
|
||||
bpy.ops.wm.keyconfig_export(filepath=filepath)
|
||||
bpy.utils.keyconfig_set(filepath)
|
||||
|
||||
def pre_cb(self, context):
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
if self.remove_active:
|
||||
preset_menu_class = getattr(bpy.types, self.preset_menu)
|
||||
preset_menu_class.bl_label = keyconfigs.active.name
|
||||
|
||||
def post_cb(self, context):
|
||||
keyconfigs = bpy.context.window_manager.keyconfigs
|
||||
if self.remove_active:
|
||||
keyconfigs.remove(keyconfigs.active)
|
||||
|
||||
|
||||
def register():
|
||||
pass
|
||||
|
||||
|
@ -768,6 +768,17 @@ class WM_OT_properties_remove(bpy.types.Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class WM_OT_keyconfig_activate(bpy.types.Operator):
|
||||
bl_idname = "wm.keyconfig_activate"
|
||||
bl_label = "Activate Keyconfig"
|
||||
|
||||
filepath = StringProperty(name="File Path", maxlen=1024)
|
||||
|
||||
def execute(self, context):
|
||||
bpy.utils.keyconfig_set(self.filepath)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def register():
|
||||
pass
|
||||
|
||||
|
@ -725,6 +725,7 @@ class USERPREF_PT_input(InputKeyMapPanel):
|
||||
sub = col.column()
|
||||
sub.label(text="Presets:")
|
||||
subrow = sub.row(align=True)
|
||||
|
||||
subrow.menu("USERPREF_MT_interaction_presets", text=bpy.types.USERPREF_MT_interaction_presets.bl_label)
|
||||
subrow.operator("wm.interaction_preset_add", text="", icon='ZOOMIN')
|
||||
subrow.operator("wm.interaction_preset_add", text="", icon='ZOOMOUT').remove_active = True
|
||||
|
@ -124,6 +124,19 @@ def _merge_keymaps(kc1, kc2):
|
||||
return merged_keymaps
|
||||
|
||||
|
||||
class PREFS_MT_keyconfigs(bpy.types.Menu):
|
||||
bl_label = "KeyPresets"
|
||||
preset_subdir = "keyconfig"
|
||||
preset_operator = "wm.keyconfig_activate"
|
||||
def draw(self, context):
|
||||
props = self.layout.operator("wm.context_set_value", text="Blender (default)")
|
||||
props.data_path = "window_manager.keyconfigs.active"
|
||||
props.value = "context.window_manager.keyconfigs.default"
|
||||
|
||||
# now draw the presets
|
||||
bpy.types.Menu.draw_preset(self, context)
|
||||
|
||||
|
||||
class InputKeyMapPanel(bpy.types.Panel):
|
||||
bl_space_type = 'USER_PREFERENCES'
|
||||
bl_label = "Input"
|
||||
@ -365,10 +378,18 @@ class InputKeyMapPanel(bpy.types.Panel):
|
||||
subsplit = sub.split()
|
||||
subcol = subsplit.column()
|
||||
|
||||
row = subcol.row()
|
||||
row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:")
|
||||
layout.context_pointer_set("keyconfig", wm.keyconfigs.active)
|
||||
row.operator("wm.keyconfig_remove", text="", icon='X')
|
||||
row = subcol.row(align=True)
|
||||
|
||||
#row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:")
|
||||
text = bpy.path.display_name(context.window_manager.keyconfigs.active.name)
|
||||
if not text:
|
||||
text = "Blender (default)"
|
||||
row.menu("PREFS_MT_keyconfigs", text=text)
|
||||
row.operator("wm.keyconfig_preset_add", text="", icon="ZOOMIN")
|
||||
row.operator("wm.keyconfig_preset_add", text="", icon="ZOOMOUT").remove_active = True
|
||||
|
||||
# layout.context_pointer_set("keyconfig", wm.keyconfigs.active)
|
||||
# row.operator("wm.keyconfig_remove", text="", icon='X')
|
||||
|
||||
row.prop(context.space_data, "filter_text", icon="VIEWZOOM")
|
||||
|
||||
@ -389,8 +410,9 @@ def export_properties(prefix, properties, lines=None):
|
||||
if lines is None:
|
||||
lines = []
|
||||
|
||||
for pname, value in properties.items():
|
||||
for pname in properties.keys():
|
||||
if not properties.is_property_hidden(pname):
|
||||
value = getattr(properties, pname)
|
||||
if isinstance(value, bpy.types.OperatorProperties):
|
||||
export_properties(prefix + "." + pname, value, lines)
|
||||
elif properties.is_property_set(pname):
|
||||
@ -501,7 +523,7 @@ 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):
|
||||
repr(list(value))
|
||||
return repr(list(value))
|
||||
else:
|
||||
print("Export key configuration: can't write ", value)
|
||||
|
||||
@ -521,6 +543,7 @@ class WM_OT_keyconfig_import(bpy.types.Operator):
|
||||
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:
|
||||
raise Exception("Filepath not set")
|
||||
@ -529,24 +552,16 @@ class WM_OT_keyconfig_import(bpy.types.Operator):
|
||||
if not f:
|
||||
raise Exception("Could not open file")
|
||||
|
||||
config_name = None
|
||||
for line in f:
|
||||
if line.startswith("kc = wm.keyconfigs.new("):
|
||||
config_name = line[24:-3]
|
||||
break
|
||||
config_name = basename(self.filepath)
|
||||
|
||||
if config_name is None:
|
||||
raise Exception("config name not found")
|
||||
|
||||
path = os.path.join(__file__, "..", "..", "cfg") # remove ui/space_userpref.py
|
||||
path = os.path.normpath(path)
|
||||
path = bpy.utils.preset_paths("keyconfig")[0] # we need some way to tell the user and system preset path
|
||||
print(path)
|
||||
|
||||
# create config folder if needed
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
|
||||
path = os.path.join(path, config_name + ".py")
|
||||
path = os.path.join(path, config_name)
|
||||
|
||||
if self.keep_original:
|
||||
shutil.copy(self.filepath, path)
|
||||
@ -554,18 +569,7 @@ class WM_OT_keyconfig_import(bpy.types.Operator):
|
||||
shutil.move(self.filepath, path)
|
||||
|
||||
# sneaky way to check we're actually running the code.
|
||||
wm = context.window_manager
|
||||
while config_name in wm.keyconfigs:
|
||||
wm.keyconfigs.remove(wm.keyconfigs[config_name])
|
||||
|
||||
wm = context.window_manager
|
||||
totmap = len(wm.keyconfigs)
|
||||
mod = __import__(config_name)
|
||||
if totmap == len(wm.keyconfigs):
|
||||
reload(mod)
|
||||
|
||||
wm = bpy.context.window_manager
|
||||
wm.keyconfigs.active = wm.keyconfigs[config_name]
|
||||
bpy.utils.keyconfig_set(path)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
@ -586,7 +590,6 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
|
||||
filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
|
||||
filter_text = BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'})
|
||||
filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
|
||||
kc_name = StringProperty(name="KeyConfig Name", description="Name to save the key config as")
|
||||
|
||||
def execute(self, context):
|
||||
if not self.filepath:
|
||||
@ -599,18 +602,10 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
|
||||
wm = context.window_manager
|
||||
kc = wm.keyconfigs.active
|
||||
|
||||
if self.kc_name != '':
|
||||
name = self.kc_name
|
||||
elif kc.name == 'Blender':
|
||||
name = os.path.splitext(os.path.basename(self.filepath))[0]
|
||||
else:
|
||||
name = kc.name
|
||||
|
||||
f.write("# Configuration %s\n" % name)
|
||||
|
||||
f.write("import bpy\n\n")
|
||||
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('%s')\n\n" % name)
|
||||
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:
|
||||
#
|
||||
@ -775,21 +770,7 @@ class WM_OT_keyconfig_remove(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
import sys
|
||||
wm = context.window_manager
|
||||
|
||||
keyconfig = wm.keyconfigs.active
|
||||
|
||||
module = sys.modules.get(keyconfig.name)
|
||||
|
||||
if module:
|
||||
path = module.__file__
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
path = module.__file__ + "c" # for .pyc
|
||||
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
wm.keyconfigs.remove(keyconfig)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
@ -2655,6 +2655,10 @@ static void rna_def_userdef_input(BlenderRNA *brna)
|
||||
RNA_def_property_collection_sdna(prop, NULL, "keymaps", NULL);
|
||||
RNA_def_property_struct_type(prop, "KeyMap");
|
||||
RNA_def_property_ui_text(prop, "Edited Keymaps", "");
|
||||
|
||||
prop= RNA_def_property(srna, "active_keyconfig", PROP_STRING, PROP_DIRPATH);
|
||||
RNA_def_property_string_sdna(prop, NULL, "keyconfigstr");
|
||||
RNA_def_property_ui_text(prop, "Key Config", "The name of the active key configuration");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_filepaths(BlenderRNA *brna)
|
||||
|
Loading…
Reference in New Issue
Block a user